diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ef516d0..3a90add 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,102 +4,124 @@ Thank you for your interest in contributing! This guide will help you understand ## 📁 Project Structure +Source layout (the runnable app is produced under **`dist/`** by `npm run build`; `dist/` is gitignored). + ``` P4RS3LT0NGV3/ +├── package.json +├── favicon.svg +├── index.template.html # HTML shell; tool *script* tags updated by inject-tool-scripts +├── css/ +│ ├── style.css +│ └── notification.css ├── js/ -│ ├── app.js # Main Vue.js application entry point -│ ├── core/ # Core feature modules (shared libraries) -│ │ ├── decoder.js # Universal decoder -│ │ ├── steganography.js # Steganography encoding/decoding -│ │ └── toolRegistry.js # Tool registry system -│ ├── bundles/ # Build-generated files (auto-created) -│ │ └── transforms-bundle.js # Generated bundle from src/transformers/ -│ ├── config/ # Configuration constants +│ ├── app.js # Vue app entry +│ ├── config/ │ │ └── constants.js -│ ├── data/ # Generated or static data files (auto-created) -│ │ ├── emojiData.js # Generated from Unicode emoji data -│ │ └── emojiCompatibility.js -│ ├── utils/ # Utility functions +│ ├── core/ # Shared logic (not tab-specific UI) +│ │ ├── decoder.js # Universal decode engine +│ │ ├── steganography.js # Emoji / invisible carriers +│ │ ├── toolRegistry.js # Registers tools, merges Vue data/methods +│ │ └── transformOptions.js +│ ├── data/ # Static data shipped with the app (see note below) +│ │ ├── anticlassifierPrompt.js +│ │ ├── emojiCompatibility.js +│ │ ├── endSequences.js +│ │ ├── glitchTokens.js +│ │ └── openrouterModels.js +│ ├── utils/ │ │ ├── clipboard.js -│ │ ├── emoji.js +│ │ ├── emoji.js # window.EmojiUtils (uses window.emojiData when present) │ │ ├── escapeParser.js │ │ ├── focus.js +│ │ ├── glitchTokens.js │ │ ├── history.js │ │ ├── notifications.js │ │ └── theme.js -│ └── tools/ # Tool implementations (Vue integration) -│ ├── Tool.js # Base class -│ ├── TransformTool.js +│ └── tools/ # One *Tool.js per tab (extends Tool.js) +│ ├── Tool.js +│ ├── AntiClassifierTool.js +│ ├── BijectionTool.js │ ├── DecodeTool.js │ ├── EmojiTool.js -│ ├── TokenadeTool.js +│ ├── GibberishTool.js │ ├── MutationTool.js -│ ├── TokenizerTool.js +│ ├── PromptCraftTool.js │ ├── SplitterTool.js -│ └── GibberishTool.js +│ ├── TokenadeTool.js +│ ├── TokenizerTool.js +│ ├── TransformTool.js +│ └── TranslateTool.js # hidden tab wiring; UI lives on Transform ├── src/ -│ ├── emojiWordMap.js # Emoji keyword mappings (merged into emojiData.js) -│ └── transformers/ # Transformer modules (source - bundled at build time) +│ ├── emojiWordMap.js # Merged into generated emoji data at build time +│ └── transformers/ # Transformer sources → bundled to dist/js/bundles/ │ ├── BaseTransformer.js -│ ├── ancient/ # Elder Futhark, Hieroglyphics, Ogham, Roman Numerals -│ ├── case/ # Camel, Kebab, Snake, Title, etc. -│ ├── cipher/ # Caesar, ROT13, Vigenère, Atbash, etc. -│ ├── encoding/ # Base64, Hex, Binary, URL, etc. -│ ├── fantasy/ # Quenya, Tengwar, Klingon, Aurebesh, Dovahzul -│ ├── format/ # Leetspeak, Pig Latin, Reverse, etc. -│ ├── special/ # Randomizer -│ ├── technical/ # Morse, NATO, Braille, Brainfuck, etc. -│ ├── unicode/ # Upside-down, Fullwidth, Bubble, etc. -│ └── visual/ # Disemvowel, Rovarspraket, Ubbi-dubbi, etc. -├── templates/ # HTML templates for tools (injected at build time) +│ ├── index.js # Generated by npm run build:index (gitignored) +│ ├── ancient/ +│ ├── case/ +│ ├── cipher/ +│ ├── encoding/ +│ ├── fantasy/ +│ ├── format/ +│ ├── special/ +│ ├── technical/ +│ ├── unicode/ +│ └── visual/ +├── templates/ # Injected into dist/index.html by inject-tool-templates +│ ├── anticlassifier.html +│ ├── bijection.html │ ├── decoder.html -│ ├── steganography.html -│ ├── transforms.html -│ ├── tokenade.html │ ├── fuzzer.html -│ ├── tokenizer.html +│ ├── gibberish.html +│ ├── promptcraft.html │ ├── splitter.html -│ └── gibberish.html -├── build/ # Build scripts -│ ├── build-index.js # Generates transformer index -│ ├── build-transforms.js # Bundles transformers into js/bundles/ -│ ├── build-emoji-data.js # Generates emojiData.js from Unicode data -│ ├── inject-tool-scripts.js # Auto-discovers and registers tools -│ └── inject-tool-templates.js # Injects templates into index.html -├── tests/ # Test suites +│ ├── steganography.html +│ ├── tokenade.html +│ ├── tokenizer.html +│ ├── transforms.html +│ └── README.md +├── build/ +│ ├── README.md +│ ├── build-index.js # Writes src/transformers/index.js +│ ├── build-transforms.js # Writes dist/js/bundles/transforms-bundle.js +│ ├── build-emoji-data.js # Writes dist/js/data/emojiData.js +│ ├── copy-static.js # Copies css/, js/, favicon → dist/ +│ ├── fetch-glitch-data.js +│ ├── inject-tool-scripts.js # Discovers tools; updates index.template.html + toolRegistry +│ ├── inject-tool-templates.js # Builds dist/index.html from index.template.html + templates/ +│ └── readme-transform-section.js # Maintainer helper for README transform list +├── tests/ │ ├── test_universal.js │ └── test_steganography_options.js -├── css/ # Stylesheets -│ ├── style.css -│ └── notification.css -├── index.template.html # Base HTML template (templates injected here) -├── index.html # Generated file (created by build process) -└── docs/ # Documentation +├── docs/ +│ ├── TOOL-SYSTEM.md +│ ├── TOOL_ARCHITECTURE.md +│ └── UI-COMPONENTS.md +├── README.md +└── CONTRIBUTING.md + +dist/ # npm run build — gitignored +├── index.html # `npm run build:templates` → from index.template.html + templates/ +├── css/ … +├── js/ … +│ ├── bundles/transforms-bundle.js +│ └── data/emojiData.js ``` +**Generated / ignored paths (also listed in `.gitignore`):** `dist/`, `src/transformers/index.js`, legacy `js/bundles/transforms-bundle.js`, `js/data/emojiData.js`, root `index.html` if present. The build updates **`dist/index.html`** only; a **root** `index.html` is not produced by the current scripts. + ## 🎯 Key Concepts ### Core vs Tools -- **`js/core/`** - Shared business logic and infrastructure - - These are **NOT** tool-specific - - Examples: - - `decoder.js` (used by DecodeTool + app.js) - - `steganography.js` (used by EmojiTool + decoder.js) - - `emojiLibrary.js` (used by EmojiTool) - - `toolRegistry.js` (ToolRegistry class - infrastructure for the tool system) - -- **Source files** (`src/`) - Source files used by build process - - `emojiWordMap.js` - Emoji keyword mappings (merged into emojiData.js during build) - - `transformers/` - Transformer modules (bundled into transforms-bundle.js) - -- **Generated files** (`js/bundles/`) - - `transforms-bundle.js` - Generated bundle from `src/transformers/` (created by `npm run build:transforms`) - -- **`js/tools/`** - Vue.js integration layer for UI features - - Each tool represents a tab/feature in the UI - - Tools use core modules and utilities for functionality - - Example: `DecodeTool.js` uses `window.universalDecode` from `core/decoder.js` +- **`js/core/`** — Shared business logic and infrastructure (not tab-specific) + - Examples: `decoder.js` (DecodeTool, decoder pipeline), `steganography.js` (EmojiTool, steg engine), `toolRegistry.js` (registers tools, merges Vue surface), `transformOptions.js` (shared transform UI helpers) +- **`js/utils/`** — Cross-cutting helpers (`clipboard`, `EmojiUtils` in `emoji.js`, notifications, theme, etc.) +- **`js/data/`** — Committed static payloads (models, prompts, glitch token data, end sequences, `emojiCompatibility.js`). **`emojiData.js`** is **not** edited here — it is **generated** to `dist/js/data/emojiData.js` by `npm run build:emoji`. +- **`src/`** — `emojiWordMap.js` feeds the emoji build; `transformers/` holds transformer modules +- **Generated bundle** — `npm run build:transforms` writes `dist/js/bundles/transforms-bundle.js` (a legacy `js/bundles/transforms-bundle.js` path may exist for older workflows and is gitignored) +- **`js/tools/`** — Vue integration: one `*Tool.js` per tab (plus `TranslateTool.js`, which is hidden and wired from the Transform tab) + - Example: `DecodeTool.js` uses the universal decode API from `core/decoder.js` ### Transformers vs Tools @@ -140,7 +162,7 @@ Transformers are the core text transformation logic. See `src/transformers/READM 1. Create a new file in the appropriate category directory: ```bash - src/transformers/ciphers/my-cipher.js + src/transformers/cipher/my-cipher.js ``` 2. Use the `BaseTransformer` class: @@ -172,7 +194,7 @@ Transformers are the core text transformation logic. See `src/transformers/READM ``` 4. Test it: - - Open `index.html` in a browser + - After `npm run build`, open **`dist/index.html`** in a browser (or use `npm start` → http://localhost:8080 if you prefer) - Your transformer will appear in the Transform tab automatically - Test encoding/decoding - Test with the Universal Decoder @@ -248,7 +270,7 @@ Tools represent UI features/tabs. Examples: Transform tab, Decoder tab, Emoji ta ``` 4. Test it: - - Open `index.html` + - After `npm run build`, open **`dist/index.html`** (or `npm start` at http://localhost:8080) - Your new tab should appear automatically - Test all functionality @@ -271,7 +293,7 @@ Utilities are shared helper functions used across the app. Currently, utility fu }; ``` -2. Add script tag to `index.html` (before `app.js`): +2. Add a script tag to **`index.template.html`** (before `app.js`), then `npm run build:copy` (or `npm run build`) so it lands in **`dist/index.html`**: ```html ``` @@ -287,7 +309,7 @@ Utilities are shared helper functions used across the app. Currently, utility fu - Document with JSDoc comments - Consider adding to existing modules if functionality is related -**Note:** The `js/utils/` directory contains utility functions: clipboard, escapeParser, focus, history, notifications, and theme. The `js/config/` directory contains configuration constants. +**Note:** Prefer `js/utils/` for shared helpers (clipboard, emoji, escapeParser, focus, glitchTokens, history, notifications, theme). Use `js/config/` for constants. ## 🧪 Testing @@ -326,12 +348,11 @@ npm run test:steg # Steganography options tests ### File Organization -- **Core modules** (`js/core/`) - Shared business logic (e.g., `decoder.js`) -- **Root-level modules** (`js/`) - Feature libraries (e.g., `steganography.js`, `emojiLibrary.js`) -- **Tools** (`js/tools/`) - Vue.js UI integration layer -- **Templates** (`templates/`) - HTML templates for tools (injected at build time) -- **Transformers** (`src/transformers/`) - Text transformation logic -- **Bundles** (`js/bundles/`) - Build-generated files +- **Core modules** (`js/core/`) — Shared logic (`decoder.js`, `steganography.js`, `toolRegistry.js`, `transformOptions.js`) +- **App entry** (`js/app.js`) — Vue bootstrap and shell behavior +- **Tools** (`js/tools/`) — Tab UI layer (`*Tool.js`) +- **Templates** (`templates/`) — Tool markup injected into `dist/index.html` +- **Transformers** (`src/transformers/`) — Transform implementations; output is `dist/js/bundles/transforms-bundle.js` ### Naming Conventions @@ -349,9 +370,9 @@ npm run build:templates ``` This: -1. Reads all `.html` files from `templates/` directory -2. Injects them into `index.html` at the `#tool-content-container` marker -3. Creates a single static HTML file for fast loading +1. Reads the ordered list of tool templates from `templates/` (see `build/inject-tool-templates.js`) +2. Injects them into **`dist/index.html`** at the `#tool-content-container` marker (from `index.template.html`) +3. Produces the static HTML file served from `dist/` **When to run:** - After editing any template in `templates/` @@ -359,21 +380,21 @@ This: ### Build Script Details -- **Directory Creation**: Build scripts automatically create output directories (`js/bundles/`, `js/data/`) if they don't exist -- **Full Build**: Run `npm run build` to execute all build steps in order -- **Individual Builds**: Each build script can be run independently +- **Directory creation**: Scripts create `dist/` (and subfolders) as needed +- **Full build**: `npm run build` runs tools injection, copy, transformer index, transform bundle, emoji data, template injection (see `package.json` and `build/README.md`) +- **Individual builds**: Each `npm run build:*` step can be run on its own -**Note:** Transformers are loaded from `js/bundles/transforms-bundle.js` which may be pre-built or generated separately. +**Note:** The browser loads transforms from **`dist/js/bundles/transforms-bundle.js`** after a successful `npm run build:transforms` (and `npm run build:copy`). ## 🐛 Debugging ### Common Issues -1. **Template changes not showing**: Run `npm run build:templates` to inject templates into `index.html` +1. **Template changes not showing**: Run `npm run build:templates` to rebuild **`dist/index.html`**, then refresh (or run `npm start` after a full `npm run build`) 2. **Tool not showing**: Check that: - - Tool is registered in `js/core/toolRegistry.js` - - Script tag is in `index.html` before `app.js` - - Template file exists in `templates/` directory + - `npm run build:tools` ran so `toolRegistry.js` and `index.template.html` include the new tool + - Script tag order in **`index.template.html`** (loads before `app.js`) + - Template file exists in `templates/` and is listed in `build/inject-tool-templates.js` when adding a new tab 3. **Tests failing**: Check file paths use `path.join(projectRoot, '...')` ### Browser Console @@ -381,23 +402,24 @@ This: - Open browser DevTools (F12) - Check console for errors - Use `window.transforms` to see all transformers -- Use `window.steganography` to access steganography functions -- Use `window.emojiLibrary` to access emoji functions +- Use `window.steganography` for steganography helpers +- Use `window.emojiData` (after build) and `window.EmojiUtils` (`js/utils/emoji.js`) for emoji lists / splitting ## 📚 Documentation -- **Project README**: `README.md` - Overview and user guide -- **Templates**: `templates/README.md` - How to edit tool templates -- **Build Process**: `build/README.md` - Build script documentation -- **Tool System**: `docs/TOOL-SYSTEM.md` - Tool architecture details -- **Code Review**: `docs/CODE-REVIEW.md` - Architecture and code review guidelines +- **Project README**: `README.md` — Overview and user guide +- **Templates**: `templates/README.md` — Editing tool templates +- **Build process**: `build/README.md` — Build scripts +- **Tool system**: `docs/TOOL-SYSTEM.md` — Templates, injection, UI vocabulary +- **Tool architecture**: `docs/TOOL_ARCHITECTURE.md` +- **UI components**: `docs/UI-COMPONENTS.md` ## ✅ Checklist Before Submitting - [ ] Code follows existing style - [ ] Tests pass (`npm test`) - [ ] Templates built (`npm run build:templates`) if template files were edited -- [ ] Tested in browser (open `index.html`) +- [ ] Tested in browser (`npm run build`, then open `dist/index.html` or `npm start`) - [ ] No console errors - [ ] Documentation updated (if needed) - [ ] JSDoc comments added (for new functions) @@ -405,7 +427,7 @@ This: ## 🤝 Questions? - Check existing code for examples -- Review `docs/CODE_REVIEW.md` for architecture details +- Review `docs/TOOL_ARCHITECTURE.md` and `docs/TOOL-SYSTEM.md` for architecture details - Look at similar features to understand patterns Thank you for contributing! 🎉 diff --git a/README.md b/README.md index 7300f94..7672fc0 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,215 @@ # 🐍 P4RS3LT0NGV3 - Universal Text Translator -A powerful web-based text transformation and steganography tool that can encode/decode text in 79+ different languages, scripts, and formats. Think of it as a universal translator for ALL alphabets and writing systems! +A powerful web-based text transformation and steganography tool with **159** built-in text transforms spanning encodings, classical and modern ciphers, Unicode styles, formatting, and niche alphabets. Think of it as a universal translator for ALL alphabets and writing systems! + +The app is a **static site**: run **`npm run build`** (after `npm install`), then open **`dist/index.html`** in your browser—no local server required. **Alternatively**, you can run it as a local app over HTTP with **`npm start`** or **`npx serve dist -l 8080`** (see [Getting Started](#getting-started) below). Core transforms, decoder, and steganography work **without** calling the cloud; features that use [OpenRouter](https://openrouter.ai/) need **network access** and an API key (see below). ## ✨ Features ### 🔐 **Steganography** -- **Emoji Steganography**: Hide messages within emojis using variation selectors -- **Invisible Text**: Encode text using Unicode Tags block (completely invisible) -- **Image Steganography**: Hide messages in images using LSB techniques +- **Emoji Steganography**: Hide messages within emojis using variation selectors (VS15/VS16 and related options; configurable bit order in Advanced Settings) +- **Invisible Text**: Encode text using Unicode Tags block (visually invisible) +- **Whitespace & zero-width steganography**: Available as transforms for research-style payloads (see transform categories) ### 🌍 **Text Transformations** -#### **Encoding & Decoding** -- **Base64** - Standard base64 encoding/decoding -- **Base32** - RFC 4648 compliant base32 encoding/decoding -- **Base58** - Bitcoin alphabet encoding/decoding -- **Base62** - 0-9A-Za-z compact encoding/decoding -- **Binary** - Convert text to/from binary representation -- **Hexadecimal** - Convert text to/from hex format -- **ASCII85** - Advanced ASCII85 encoding/decoding -- **URL Encode** - URL-safe encoding/decoding -- **HTML Entities** - HTML entity encoding/decoding +Categories match the Transform tab and the folders under `src/transformers/` (each transformer’s `name` as shown in the UI). Short descriptions explain what each transform does. -#### **Ciphers & Codes** -- **Caesar Cipher** - Classic shift cipher with configurable offset -- **ROT13** - Simple rotation cipher -- **ROT47** - Extended rotation cipher for ASCII 33-126 -- **Morse Code** - International Morse code with proper spacing +#### **Ancient** +- **Elder Futhark** - Germanic Elder Futhark runes +- **Hieroglyphics** - Egyptian hieroglyph-style mapping +- **Ogham (Celtic)** - Celtic Ogham tree alphabet +- **Roman Numerals** - Arabic numerals ↔ Roman numerals + +#### **Case** +- **Alternating Case** - Alternate uppercase and lowercase per letter (first letter upper or lower) +- **camelCase** - lowerCamelCase for identifiers +- **kebab-case** - kebab-case for slugs and identifiers +- **Random Case** - Random casing per character +- **Sentence Case** - Capitalize the first letter of each sentence +- **snake_case** - snake_case for identifiers +- **Title Case** - Capitalize each word + +#### **Cipher** +- **ADFGX Cipher** - WWI ADFGVX-style polybius + column transposition +- **Affine Cipher** - Affine substitution (ax + b mod 26) +- **Atbash Cipher** - Reverse-alphabet substitution (A↔Z) +- **Autokey Cipher** - Key stream mixed with plaintext (autokey) +- **Baconian Cipher** - Five-letter groups hiding A/B (Bacon biliteral) +- **Beaufort Cipher** - Beaufort key-table polyalphabetic cipher +- **Bifid Cipher** - Polybius square + row/column interleaving +- **Caesar Cipher** - Classic alphabet shift (configurable) +- **Columnar Transposition** - Columnar transposition with a keyword +- **Four-Square Cipher** - Four 5×5 squares; digraph substitution +- **Gronsfeld Cipher** - Vigenère family with numeric key +- **Hill Cipher** - Matrix-based multi-letter substitution +- **Homophonic Cipher** - Multiple ciphertext symbols per plaintext letter +- **Nihilist Cipher** - Keyed Polybius + additive encryption +- **Pigpen Cipher** - Masonic / pigpen grid symbols +- **Playfair Cipher** - Digraph cipher on a 5×5 square +- **Polybius Square** - Letter ↔ grid coordinates +- **Porta Cipher** - Porta table polyalphabetic cipher +- **Rail Fence** - Zig-zag rail-fence transposition +- **ROT128** - UTF-16 code unit rotation by 128 +- **ROT13** - Rotate Latin letters by 13 places +- **ROT18** - Rotate printable ASCII (33–126) by 18 +- **ROT47** - Rotate printable ASCII (33–126) by 47 +- **ROT5** - Rotate digits 0–9 by 5 +- **ROT8000** - Plane-0 Unicode BMP rotation cipher +- **Scytale Cipher** - Wrap-around strip (scytale) transposition +- **Trifid Cipher** - Three Polybius cubes + trifid grouping +- **Two-Square Cipher** - Digraph cipher with two Playfair squares +- **Vigenère Cipher** - Polyalphabetic cipher with repeating keyword +- **XOR Cipher** - XOR with a repeating key + +#### **Encoding** +- **ASCII85** - Ascii85 / Adobe-style base-85 encoding +- **Base122** - Binary → 122 printable ASCII characters +- **Base32** - RFC 4648 Base32 +- **Base36** - Base36 (0–9, A–Z) +- **Base45** - Base45 byte encoding +- **Base58** - Bitcoin-style Base58 (no 0/O/I/l) +- **Base62** - Base62 (0–9, A–Z, a–z) +- **Base64** - Standard Base64 +- **Base64 URL** - Base64url (URL-safe alphabet) +- **Base91** - basE91 / Ascii91 encoding +- **Baudot Code (ITA2)** - Five-bit telegraph / ITA2 +- **Binary Coded Decimal** - Decimal digits as BCD nibbles +- **Binary** - Text bytes ↔ binary strings +- **EBCDIC** - EBCDIC byte encoding +- **Emoji Encoding** - Payload encoded with emoji +- **Gray Code** - Binary Gray code +- **Hexadecimal** - Hex encode/decode bytes +- **HTML Entities** - HTML entity escape / unescape +- **Invisible Text** - Unicode Tags / invisible carrier encoding +- **Quoted-Printable** - MIME quoted-printable +- **Unicode Code Points** - Characters ↔ U+XXXX code points +- **URL Encode** - application/x-www-form-urlencoded +- **Uuencoding** - Classic uuencode / uudecode +- **YEnc** - yEnc line-oriented binary encoding +- **Z85** - ZeroMQ Z85 encoding + +#### **Fantasy** +- **Aurebesh (Star Wars)** - Galactic Basic Aurebesh alphabet +- **Dovahzul (Dragon)** - Skyrim Dovahzul transliteration +- **Klingon** - Klingon transliteration +- **Quenya (Tolkien Elvish)** - Tolkien Quenya mapping +- **Tengwar Script** - Elvish Tengwar script + +#### **Format** +- **Bitwise NOT** - UTF-8 bytes NOT'd per byte; encode output is hex (decode pastes hex back to text) +- **Boustrophedon** - Serpentine / alternating line direction +- **Capitalize Words** - Capitalize the first letter of each word +- **Indent** - Add leading spaces to each line (configurable width) +- **Javanais** - French “javanais” vowel-insertion game +- **Latin Gibberish** - Latin-flavored pseudo-text +- **Leetspeak** - 1337-style character substitutions +- **Letters Only** - Keep letters; strip other characters +- **Letters & Numbers Only** - Alphanumeric only +- **Line Numbers** - Prefix lines with numbers (start and column width configurable) +- **Louchebem** - French argot (loucherbem-style) +- **Lowercase All** - Lowercase entire text +- **Mirror Digits** - Mirror digits 0–9 visually +- **Numbers Only** - Digits only +- **Pig Latin** - English Pig Latin +- **QWERTY Right Shift** - Map keys to the key to the right on QWERTY +- **Remove Accents** - Strip diacritics / combining marks +- **Remove Consonants** - Remove consonant letters +- **Remove Duplicates** - Remove duplicate lines +- **Remove Extra Spaces** - Collapse runs of spaces +- **Remove HTML Tags** - Strip HTML/XML tags +- **Remove Newlines** - Remove line breaks +- **Remove Numbers** - Remove digit characters +- **Remove Punctuation** - Remove punctuation +- **Remove Tabs** - Remove tab characters +- **Remove Zero Width** - Strip zero-width characters +- **Reverse Words** - Reverse order of words +- **Reverse Text** - Reverse character order +- **Shuffle Characters** - Shuffle characters (random order) +- **Shuffle Words** - Shuffle word order +- **Spaces Remover** - Remove space characters +- **Text Justify** - Pad each line to a fixed width (left, right, or center); not word-spacing justify +- **Uppercase All** - Uppercase entire text +- **Toggle Case** - Swap case of each letter +- **Whitespace Steganography** - Hide bits in whitespace patterns +- **Word Wrap** - Break long lines at spaces so each line fits a maximum width +- **Zero-Width Steganography** - Hide data with zero-width characters + +#### **Special** +- **Random Mix** - Pick random transforms and chain them + +#### **Technical** +- **A1Z26** - A=1 … Z=26 letter numbering +- **Braille** - Unicode Braille patterns +- **Brainfuck** - Text ↔ Brainfuck program +- **ICAO Spelling Alphabet** - ICAO radiotelephony spelling +- **ITU Spelling Alphabet** - ITU phonetic / spelling alphabet +- **Maritime Signal Flags** - International maritime signal flags +- **Morse Code** - International Morse code - **NATO Phonetic** - NATO phonetic alphabet -- **Vigenère Cipher** - Polyalphabetic cipher (default key "KEY") -- **Rail Fence (3 Rails)** - Zig-zag transposition cipher +- **Semaphore Flags** - Flag semaphore arm positions +- **Tap Code** - Polybius / tap / prison code -#### **Visual Transformations** -- **Upside Down** - Flip text upside down using Unicode characters -- **Full Width** - Convert to full-width Unicode characters -- **Small Caps** - Convert to small capital letters -- **Bubble Text** - Enclose letters in circles -- **Braille** - Convert to Braille patterns -- **Strikethrough** - Add strikethrough using combining characters -- **Underline** - Add underlines using combining characters +#### **Unicode** +- **Bold Italic** - Mathematical sans-serif bold italic +- **Bold** - Mathematical bold +- **Bubble** - Circled / “bubble” letters +- **Chemical Symbols** - Chemical element symbols +- **Circled** - Circled Unicode letters +- **Cursive** - Mathematical script / cursive +- **Cyrillic Stylized** - Latin → Cyrillic lookalike letters +- **Dashed Underline** - Combining dashed underline +- **Dotted Underline** - Combining dotted underline +- **Double-Struck** - Mathematical double-struck +- **Fraktur** - Mathematical Fraktur / Gothic +- **Full Width** - Fullwidth Latin (and related) forms +- **Greek Letters** - Greek letter replacements +- **Hiragana** - Rough Romaji → Hiragana +- **Italic** - Mathematical italic +- **Katakana** - Rough Romaji → Katakana +- **Mathematical Notation** - Mathematical alphanumeric symbols +- **Medieval** - Medieval Unicode letterforms +- **Mirror Text** - Left–right mirrored characters +- **Monospace** - Mathematical monospace +- **Negative Squared** - Negative circled / squared letters +- **Overline** - Overline combining marks +- **Parenthesized** - Parenthesized Latin letters +- **Regional Indicator Letters** - Regional-indicator flag letters +- **Small Caps** - Small capitals (Unicode) +- **Squared** - Squared / enclosed alphanumeric +- **Strikethrough** - Strikethrough combining characters +- **Subscript** - Unicode subscripts +- **Superscript** - Unicode superscripts +- **Underline** - Underline combining characters +- **Upside Down** - Upside-down Unicode letters +- **Vaporwave** - Fullwidth + aesthetic spacing +- **Wavy Underline** - Wavy underline combining marks +- **Wide Spacing** - Insert wide spaces between characters +- **Wingdings** - Wingdings-style symbol mapping +- **Zalgo** - Stacked combining marks (“glitch” text) -#### **Unicode Styles** -- **Medieval** - Gothic/medieval style characters -- **Cursive** - Cursive/script style characters -- **Monospace** - Monospace mathematical characters -- **Double-Struck** - Mathematical double-struck characters -- **Greek Letters** - Greek alphabet characters -- **Wingdings** - Symbol font characters -- **Fraktur** - Mathematical Fraktur alphabet -- **Cyrillic Stylized** - Latin letters mapped to similar Cyrillic glyphs -- **Katakana** - Romaji to Katakana (approximate, reversible) -- **Hiragana** - Romaji to Hiragana (approximate, reversible) -- **Roman Numerals** - Numbers to Roman numerals (reversible) +#### **Visual** +- **Disemvowel** - Remove vowels (speech game) +- **Emoji Speak** - Emoji-heavy “speak” transform +- **Rövarspråket** - Swedish consonant-doubling game +- **Ubbi Dubbi** - Insert “ub” before vowel sounds -#### **Fantasy Languages** 🧙♂️ -- **Quenya (Tolkien Elvish)** - High Elvish language from Lord of the Rings -- **Tengwar Script** - Elvish writing system -- **Klingon** - Star Trek Klingon language -- **Aurebesh (Star Wars)** - Galactic Basic alphabet -- **Dovahzul (Dragon)** - Dragon language from Skyrim +### 🛠️ **Tools** (tabs) -#### **Ancient Scripts** 🏛️ -- **Elder Futhark** - Ancient Germanic runes -- **Hieroglyphics** - Egyptian hieroglyphic symbols -- **Ogham (Celtic)** - Celtic tree alphabet -- **Semaphore Flags** - Flag signaling system +Tabs appear in **UI order** below. **OpenRouter** (optional or required per tool) uses the key in **Advanced Settings** — see **OpenRouter API Key Setup** below. -#### **Technical Codes** ⚙️ -- **Brainfuck** - Esoteric programming language -- **Mathematical Notation** - Mathematical script characters -- **Chemical Symbols** - Chemical element abbreviations +### 🔤 **Transform** -#### **Formatting** -- **Pig Latin** - Simple word transformation -- **Leetspeak** - 1337 speak with number substitutions -- **Vaporwave** - Aesthetic spacing -- **Zalgo** - Glitch text with combining marks -- **Mirror Text** - Reversed text - -### 🔍 **Universal Decoder** -- **Smart Detection**: Automatically detects and decodes any supported format -- **Priority Matching**: Prioritizes decoding based on active transform -- **Fallback Methods**: Tries all available decoders if primary fails -- **Real-time Processing**: Instant decoding as you type +- **159 Transforms**: Encodings, ciphers, Unicode styles, formats, and more (full catalog above). +- **Categories**: Grouped sections you can **reorder**; quick-jump legend; **randomizer** last. +- **Favorites & last used**: Pin transforms and recall recent picks. +- **Per-transform options**: Gear icon where a transform exposes settings. +- **Keyboard shortcut**: **T** (shown in the tab title). ### 🌐 **AI Translation** (via OpenRouter) + +*Lives on the **Transform** tab — not a separate tab.* + - **20+ Languages**: Major world languages (Spanish, French, Chinese, Japanese, Korean, etc.) - **Dead & Exotic Languages**: Latin, Sanskrit, Ancient Greek, Sumerian, Akkadian, Old English, and more - **Custom Languages**: Add any language on-the-fly @@ -92,23 +217,73 @@ A powerful web-based text transformation and steganography tool that can encode/ - **TranslateGemma Prompt Format**: Uses Google's optimized prompt template for high-quality translation - **Auto-Fallback**: If a model is unavailable, automatically falls back to Gemma 3 27B -### 🪄 **PromptCraft** (AI Prompt Mutation) -- **9 Mutation Strategies**: Rephrase, Obfuscate, Role-Play Wrap, Multi-Language, Expand, Compress, Metaphor, Fragment, and Custom -- **48+ Models**: Frontier (Claude, GPT, Gemini, Grok), Reasoning (o3, o4, DeepSeek R1), Fast (Haiku, Mini), Code-specialized, Open Source (Llama, Qwen), and Search/Research models -- **Parallel Variants**: Generate 1-10 variants simultaneously with diverse temperature settings -- **Copy & Iterate**: Copy any variant or feed it back as input for iterative refinement +### 🔍 **Decoder** (Universal Decoder) -### 🛠️ **Available Tools** -- **Universal Decoder**: Auto-detect and decode any supported format -- **Text Transforms**: 79+ encoding, cipher, and transformation options -- **AI Translation**: Translate to 20+ languages via OpenRouter (built into Transforms tab) -- **PromptCraft**: AI-powered prompt mutation and crafting (dedicated tab) -- **Steganography**: Emoji and invisible text steganography -- **Tokenade Generator**: High-density token payload builder -- **Mutation Lab (Fuzzer)**: Generate diverse text mutations -- **Tokenizer Visualization**: Visualize tokenization for various engines -- **Message Splitter**: Split text into multiple copyable chunks -- **Gibberish Generator**: Create gibberish dictionaries and character removal variants +- **Smart detection**: Runs format detectors and decode paths for supported transforms. +- **Priority matching**: When a transform is active, decoding prefers that format first. +- **Fallback**: Tries other decoders if the primary guess fails. +- **Real-time**: Updates as you type. +- **Script & language hints**: Unicode script ranges and Latin word-marker heuristics for common languages. +- **AI translate to English** (optional, OpenRouter): When text looks foreign, optional one-shot translate to English. +- **Keyboard shortcut**: **D**. + +### 😀 **Emoji** (Steganography) + +- **Emoji carriers**: Hide data using variation selectors and supported emoji carriers; pick from the emoji grid. +- **Invisible text**: Switch to Unicode Tags–style invisible encoding where available. +- **Encode & decode**: Separate flows for hiding and recovering text. +- **Advanced Settings**: Bit order, VS choices, and other steganography tuning (sliders icon). +- **Keyboard shortcut**: **H** (shown in the tab title). + +### 💣 **Tokenade** + +- **Token bomb builder**: Depth, breadth, repeats, separators (e.g. ZWSP), variation selectors, noise. +- **Carriers & payloads**: Emoji carriers, text payloads, combining options. +- **Safety**: Warns when estimated output crosses a **danger** token threshold. + +### 🧪 **Mutation Lab** + +- **Batch mutations**: Generate many variants from one input (count configurable). +- **Seed**: Optional deterministic runs. +- **Toggles**: Random mix, zero-width, Unicode noise, Zalgo, whitespace, casing, encode/shuffle. +- **Random Mix**: Can chain the project’s random transform mixer when enabled. + +### 📊 **Tokenizer** + +- **Engines**: UTF-8 **bytes**, **words**, or **GPT BPE** (**cl100k**, **o200k**, **p50k**, **r50k**) via `gpt-tokenizer` (CDN). +- **Visualization**: Token list with IDs/pieces; **character** and **word** counts. +- **Live updates**: Re-tokenizes when input or engine changes. + +### ↔️ **Bijection** + +- **Custom mappings**: Character-to-number (and related) “alphapr”-style maps for research payloads. +- **Controls**: Mapping type, budget, optional examples. +- **Output**: Generated mappings and payloads ready to copy. + +### ✂️ **Splitter** + +- **Split modes**: By chunk size, **word**, **sentence**, **line**, **regex pattern**, or **token** count (GPT tokenizer). +- **Transform chain**: Optionally run transforms on each piece. +- **Wrapping**: Start/end templates; `{n}` iterator marker; single-line vs multiline copy. + +### 💬 **Gibberish** + +- **Dictionary mode**: Seeded random gibberish over a configurable character set. +- **Removal mode**: Random or **specific** letter removal with batch **variations** and min/max strip lengths. + +### 🪄 **PromptCraft** (via OpenRouter) + +- **9 Mutation Strategies**: Rephrase, Obfuscate, Role-Play Wrap, Multi-Language, Expand, Compress, Metaphor, Fragment, and Custom +- **48+ Models**: Frontier (Claude, GPT, Gemini, Grok), Reasoning (o3, o4, DeepSeek R1), Fast (Haiku, Mini), Code-specialized, Open Source (Llama, Qwen), and Search/Research +models +- **Parallel Variants**: Generate 1-10 variants simultaneously with diverse temperature settings +- **Copy & iterate**: Copy any variant or feed it back as input for iterative refinement + +### 🤖 **Anti-Classifier** (via OpenRouter) + +- **Purpose**: Syntactic / paraphrase-style rewrites for research-style prompts. +- **Controls**: Model, temperature, max tokens. +- **Same key**: Uses the same OpenRouter API key as Translation and PromptCraft. ### 📱 **User Experience** - **Dark/Light Theme**: Toggle between themes @@ -117,9 +292,12 @@ A powerful web-based text transformation and steganography tool that can encode/ - **Keyboard Shortcuts**: Quick access to features - **Responsive Design**: Works on all device sizes - **Accessibility**: Screen reader friendly with proper ARIA labels +- **Side panels**: Glitch token browser (optional data), end-sequence / delimiter strings for research, and **Advanced Settings** (OpenRouter key, steganography tuning) ### 🔑 **OpenRouter API Key Setup** -Translation and PromptCraft features require an [OpenRouter](https://openrouter.ai/) API key: + +**AI Translation**, **PromptCraft**, and **Anti-Classifier** require an [OpenRouter](https://openrouter.ai/) API key. **Decoder**’s optional “translate to English” also uses OpenRouter when enabled. + 1. Create an account at [openrouter.ai](https://openrouter.ai/) 2. Generate an API key (starts with `sk-or-...`) 3. In P4RS3LT0NGV3, click the **sliders icon** (top-right) to open **Advanced Settings** @@ -130,39 +308,50 @@ Translation and PromptCraft features require an [OpenRouter](https://openrouter. ## 🚀 **Getting Started** -### **Quick Start (Built Version)** -1. Run the build process (see Development Setup below) -2. Open `dist/index.html` in any modern web browser -3. Type text in the input field -4. Choose a transformation from the categorized buttons -5. Click any transform button to apply and auto-copy -6. Use the Universal Decoder to decode any encoded text +### **Quick Start (local)** +1. `npm install` then `npm run build` (generates the **`dist/`** folder — it is **not** checked into git; you must build after clone or source changes) +2. Open **`dist/index.html`** in Chrome, Firefox, Safari, or another browser (double-click the file or use **File → Open**). + +**Alternative — run as a local app (npm / npx):** From the project root, after `npm install` and `npm run build`, use **`npm start`** (runs [`serve`](https://github.com/vercel/serve) on port **8080**) or **`npx serve dist -l 8080`**. Then open **http://localhost:8080** — same UI, stable URL you can bookmark. **`npm run preview`** runs a full **`npm run build`** and then serves **`dist/`** in one step. ### **Development Setup** ```bash # Install dependencies npm install -# Build all assets (required before use): -# - Copies static files to dist/ -# - Builds transform bundle from source files -# - Generates emoji data -# - Injects tool templates into dist/index.html +# Build all assets (required before use). Order matches package.json: +# build:tools → build:copy → build:index → build:transforms → build:emoji → build:templates npm run build # Or build individual components: +npm run build:tools # Auto-discover tools, inject script tags into dist/index.html npm run build:copy # Copy static files to dist/ -npm run build:transforms # Bundle all transformers to dist/js/bundles/ +npm run build:index # Generate src/transformers/index.js (ES module index) +npm run build:transforms # Bundle all transformers to dist/js/bundles/transforms-bundle.js npm run build:emoji # Generate emoji data to dist/js/data/ -npm run build:templates # Inject tool HTML templates to dist/index.html -npm run build:index # Generate transformer index +npm run build:templates # Inject tool HTML templates into dist/index.html # Run tests npm test # Run universal decoder tests npm run test:universal # Same as above npm run test:steg # Test steganography options +npm run test:all # Universal + steganography tests + +# Optional: serve dist/ over HTTP instead of opening dist/index.html directly +npm start # http://localhost:8080 +npm run preview # npm run build, then serve dist/ ``` +### **Documentation & maintainer notes** + +| Doc | Purpose | +|-----|---------| +| [CONTRIBUTING.md](CONTRIBUTING.md) | Adding transformers, tools, tests | +| [docs/TOOL-SYSTEM.md](docs/TOOL-SYSTEM.md) | Tool templates, build injection, shared UI classes | +| [build/README.md](build/README.md) | What each `build:*` script does | +| [templates/README.md](templates/README.md) | Editing tool HTML templates | + +**Keeping the transform list in this README in sync:** when you add or rename a transformer, add a one-line description to `DESCRIPTIONS` in `build/readme-transform-section.js`, run `node build/readme-transform-section.js`, and replace the **Text Transformations** section here (details in [src/transformers/README.md](src/transformers/README.md)). ## 🛠️ **Technical Details** @@ -171,11 +360,12 @@ npm run test:steg # Test steganography options - **Tool System**: Modular tool registry with build-time template injection - **Encoding**: UTF-8 with proper Unicode handling - **Steganography**: Variation selectors and Tags Unicode block +- **Transforms**: Individual transformer modules live under `src/transformers/` (159; the bundle is generated by `npm run build:transforms`) - **Build Process**: - - Transformers are bundled from `src/transformers/` into `js/bundles/transforms-bundle.js` - - Tool templates are injected from `templates/` into `index.html` - - Emoji data is generated from Unicode specifications - - All build steps are required before the app can run + - `npm run build` writes the runnable app under `dist/` (ignored by git in most setups) + - Transformers are bundled from `src/transformers/` to `dist/js/bundles/transforms-bundle.js` + - Tool templates are injected from `templates/` into `dist/index.html` + - Emoji data is generated to `dist/js/data/` ### **Browser Support** - Chrome/Edge 80+ @@ -200,7 +390,7 @@ npm run test:steg # Test steganography options - 🆕 **AI Translation**: Translate to 20+ languages (including dead/exotic) via OpenRouter using TranslateGemma prompt format - 🆕 **PromptCraft Tool**: AI-powered prompt mutation with 9 strategies and 48+ models - 🆕 **OpenRouter Integration**: Unified API key management for all AI-powered features -- 🆕 **79+ Transformations**: Added fantasy, ancient, and technical scripts +- 🆕 **159 Transformations**: Full catalog of encodings, ciphers, Unicode styles, fantasy and ancient scripts, and technical codes (see README transform list) - 🆕 **More Encodings/Ciphers**: Base58, Base62, Vigenère, Rail Fence, Roman Numerals - 🆕 **Category Organization**: Better organized transform categories - 🆕 **Enhanced Styling**: New color schemes for each category diff --git a/build/fetch-glitch-data.js b/build/fetch-glitch-data.js new file mode 100644 index 0000000..dc9eddb --- /dev/null +++ b/build/fetch-glitch-data.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node +/** + * Script to fetch and format glitch token data from the repository + * This script reads the JSON from stdin and writes it as a JavaScript file + */ + +const fs = require('fs'); +const path = require('path'); + +// Read JSON from stdin +let jsonData = ''; +process.stdin.setEncoding('utf8'); + +process.stdin.on('data', (chunk) => { + jsonData += chunk; +}); + +process.stdin.on('end', () => { + try { + const json = JSON.parse(jsonData); + + const output = `/** + * Glitch Tokens Data + * Contains glitch token data structure (LLM vocabulary anomalies) + * + * Source: https://github.com/elder-plinius/L1B3RT4S + * Format: AGGREGLITCH structure + * + * This file contains the complete glitch token data from the AGGREGLITCH repository. + * Last updated: ${json._metadata.last_updated} + * Total tokens cataloged: ${json._metadata.total_tokens_cataloged} + */ + +window.glitchTokensData = ${JSON.stringify(json, null, 4)}; +`; + + const outputPath = path.join(__dirname, '..', 'js', 'data', 'glitchTokens.js'); + fs.writeFileSync(outputPath, output, 'utf8'); + + console.log(`✅ Glitch token data written successfully!`); + console.log(` File: ${outputPath}`); + console.log(` Total tokens: ${json._metadata.total_tokens_cataloged}`); + console.log(` Last updated: ${json._metadata.last_updated}`); + } catch (error) { + console.error('Error processing JSON:', error.message); + process.exit(1); + } +}); + diff --git a/build/inject-tool-templates.js b/build/inject-tool-templates.js index 0d5c1d2..d17796c 100644 --- a/build/inject-tool-templates.js +++ b/build/inject-tool-templates.js @@ -11,6 +11,7 @@ console.log('📝 Injecting tool templates into index.html...\n'); // Template files in order const templateFiles = [ + 'anticlassifier.html', 'decoder.html', 'steganography.html', 'transforms.html', @@ -18,6 +19,7 @@ const templateFiles = [ 'tokenade.html', 'fuzzer.html', 'tokenizer.html', + 'bijection.html', 'splitter.html', 'gibberish.html' ]; diff --git a/css/style.css b/css/style.css index 0d9e52f..c7c92e8 100644 --- a/css/style.css +++ b/css/style.css @@ -22,6 +22,9 @@ --input-border: #404040; --section-divider: #404040; --focus-shadow: 0 0 0 2px rgba(100, 181, 246, 0.4); + --panel-shadow-soft: 0 2px 8px rgba(0, 0, 0, 0.1); + --sidebar-edge-shadow: -5px 0 15px rgba(0, 0, 0, 0.3); + --sidebar-width: 420px; /* Transform category colors */ --encoding-color: #7e57c2; /* Purple for encoding/decoding */ @@ -317,6 +320,84 @@ body { flex: 0 1 auto; } +/* Spacing utilities (tool templates) */ +.u-mb-8 { margin-bottom: 8px; } +.u-mb-16 { margin-bottom: 16px; } +.u-mt-16 { margin-top: 16px; } + +/* Textarea + absolutely positioned .copy-button */ +.textarea-copy-wrap { + position: relative; +} + +/* Tokenizer token grid */ +.token-tiles.tokenizer-tiles { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.token-chip.token-chip--tokenizer { + background: var(--button-bg); + border: 1px solid var(--input-border); + padding: 6px 8px; + border-radius: 6px; + font-family: 'Fira Code', monospace; +} + +.token-chip__idx { + opacity: 0.75; + margin-right: 6px; +} + +.token-chip__id { + opacity: 0.6; + margin-left: 6px; +} + +/* Fuzzer case list */ +.fuzzer-list { + display: flex; + flex-direction: column; + gap: 8px; +} + +.fuzzer-case-row { + display: flex; + align-items: center; + gap: 8px; +} + +.fuzzer-case-index { + opacity: 0.7; + min-width: 32px; +} + +.fuzzer-case-textarea { + flex: 1; + min-height: 46px; +} + +/* Decoder: method select beside label (override full-width select defaults) */ +select.decoder-method-select { + margin-left: 15px; + padding: 5px 10px; + border-radius: 6px; + width: auto; + max-width: min(100%, 320px); +} + +/* Tokenade text payload block label */ +.tokenade-field-label { + display: block; + width: 100%; + margin-bottom: 15px; +} + +.tokenade-field-label input[type="text"] { + width: 100%; +} + /* Button variants */ .btn-secondary { @@ -677,6 +758,44 @@ h1, h2, h3, h4, h5 { color: var(--accent-color); } +/* Mobile-only: compact tool picker (tab bar hidden ≤768px) */ +.tab-tool-select { + display: none; + margin-bottom: 16px; +} + +.tab-tool-select label { + display: block; + font-size: 0.72rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--text-muted); + margin-bottom: 6px; +} + +.mobile-tool-dropdown { + width: 100%; + min-height: 44px; + padding: 10px 12px; + font-size: 0.95rem; + border-radius: 6px; + border: 1px solid var(--input-border); + background: var(--input-bg); + color: var(--text-color); + cursor: pointer; + -webkit-appearance: none; + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23999' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 12px center; + padding-right: 36px; +} + +body.dark-theme .mobile-tool-dropdown { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23b0b0b0' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); +} + .transform-button.active { background-color: var(--accent-color); color: var(--main-bg-color); @@ -707,8 +826,8 @@ h1, h2, h3, h4, h5 { .output-container { position: relative; } -.fuzzer-list .token-chip { position: relative; } -.fuzzer-list .token-chip .copy-button { position: static; } +.fuzzer-list .fuzzer-case-row { position: relative; } +.fuzzer-list .fuzzer-case-row .copy-button { position: static; } .section-header { margin-bottom: 15px; @@ -1282,8 +1401,11 @@ h1, h2, h3, h4, h5 { /* Transform layout */ .transform-layout { + display: flex; + flex-direction: column; gap: 24px; margin-top: 16px; + position: relative; } .transform-section { @@ -1418,7 +1540,7 @@ h1, h2, h3, h4, h5 { background: var(--secondary-bg); border-radius: 8px; padding: 16px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + box-shadow: var(--panel-shadow-soft); transition: all 0.3s ease; position: relative; border-left: none; @@ -1499,7 +1621,9 @@ h1, h2, h3, h4, h5 { border-left-color: var(--accent-color); } -.last-used-section .transform-buttons .transform-button-group { +.last-used-section .transform-buttons .transform-button-group, +#category-randomizer .transform-buttons .transform-button-group, +.favorites-section .transform-buttons .transform-button-group { width: 100%; } @@ -1551,6 +1675,257 @@ h1, h2, h3, h4, h5 { border-left-color: var(--case-color); } +.category-title.transform-category-translate { + border-left-color: var(--ancient-color); + text-transform: none; + margin-bottom: 10px; + padding-bottom: 6px; +} + +.translate-inline-section { + padding: 14px 16px; +} + +.translate-inline-section .translate-powered-by { + font-size: 0.65rem; + font-weight: 400; + opacity: 0.8; + margin-left: 6px; + color: var(--accent-color); +} + +.translate-inline-section .pc-error { + margin-bottom: 8px; +} + +.pc-error { + color: #f07178; + font-size: 0.85rem; + padding: 8px 10px; + background: rgba(240, 113, 120, 0.08); + border: 1px solid rgba(240, 113, 120, 0.35); + border-radius: 4px; +} + +.translate-loading { + font-size: 0.85rem; + margin-bottom: 8px; + opacity: 0.9; +} + +.translate-model-picker { + margin-bottom: 10px; +} + +.translate-model-select { + width: 100%; + padding: 6px 10px; + font-size: 0.8rem; + border-radius: 4px; + border: 1px solid var(--input-border); + background: var(--input-bg); + color: var(--text-color); + box-sizing: border-box; +} + +.translate-subsection { + margin-bottom: 10px; +} + +.translate-subsection:last-child { + margin-bottom: 0; +} + +.translate-subsection-label { + display: flex; + align-items: center; + gap: 6px; + font-size: 0.72rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; + color: var(--text-color); + opacity: 0.88; + margin-bottom: 6px; +} + +button.translate-custom-label-btn { + width: 100%; + margin: 0 0 6px 0; + padding: 6px 8px; + font: inherit; + font-size: 0.72rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; + text-align: left; + color: var(--text-color); + opacity: 0.88; + background: transparent; + border: 1px solid transparent; + border-radius: 6px; + cursor: pointer; + display: flex; + align-items: center; + gap: 6px; + box-sizing: border-box; + transition: background 0.15s ease, border-color 0.15s ease; +} + +button.translate-custom-label-btn:hover { + opacity: 1; + background: rgba(var(--ancient-color-rgb), 0.08); + border-color: var(--input-border); +} + +button.translate-custom-label-btn:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(var(--ancient-color-rgb), 0.35); +} + +.translate-custom-toggle-end { + margin-left: auto; + padding: 2px 8px; + font-size: 0.75rem; + border-radius: 4px; + border: 1px solid var(--input-border); + background: var(--button-bg); + color: var(--text-color); + display: inline-flex; + align-items: center; + justify-content: center; +} + +button.translate-custom-label-btn:hover .translate-custom-toggle-end { + background: var(--button-hover-bg); + border-color: var(--ancient-color); + color: var(--ancient-color); +} + +.translate-lang-grid { + display: flex; + flex-wrap: wrap; + gap: 8px; + width: 100%; + box-sizing: border-box; +} + +.translate-lang-btn { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 4px; + padding: 8px 6px 20px; + min-height: 58px; + border-radius: 4px; + font-size: 0.75rem; + font-weight: 500; + border: 1px solid var(--input-border); + color: var(--text-color); + cursor: pointer; + transition: all 0.2s ease; + box-sizing: border-box; + background: linear-gradient(to right, rgba(var(--ancient-color-rgb), 0.06), var(--button-bg)); +} + +.translate-lang-btn:hover:not(:disabled) { + background: linear-gradient(to right, rgba(var(--ancient-color-rgb), 0.14), var(--button-hover-bg)); + box-shadow: 0 2px 8px rgba(var(--ancient-color-rgb), 0.18); +} + +.translate-lang-btn:disabled { + opacity: 0.55; + cursor: wait; +} + +.translate-lang-exotic { + background: linear-gradient(to right, rgba(var(--ancient-color-rgb), 0.09), var(--button-bg)); +} + +.translate-lang-custom { + position: relative; + padding-right: 20px; +} + +.translate-lang-favorite.favorite-icon { + right: 6px; + bottom: 5px; + font-size: 0.72rem; +} + +.translate-custom-flag { + color: var(--ancient-color); + font-size: 1.1rem; +} + +.translate-flag { + font-size: 1.05rem; + line-height: 1; +} + +.translate-name { + line-height: 1.2; + text-align: center; +} + +.translate-remove { + position: absolute; + top: 2px; + right: 4px; + font-size: 1rem; + line-height: 1; + opacity: 0.55; + cursor: pointer; + padding: 0 2px; +} + +.translate-remove:hover { + opacity: 1; + color: #f07178; +} + +.translate-add-form { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-bottom: 8px; + align-items: center; +} + +.translate-add-form input { + flex: 1; + min-width: 160px; + padding: 6px 10px; + font-size: 0.8rem; + border-radius: 4px; + border: 1px solid var(--input-border); + background: var(--input-bg); + color: var(--text-color); +} + +.translate-add-btn { + padding: 6px 12px; + font-size: 0.8rem; + border-radius: 4px; + border: 1px solid var(--input-border); + background: var(--button-bg); + color: var(--text-color); + cursor: pointer; +} + +.translate-add-btn:hover:not(:disabled) { + background: var(--button-hover-bg); + border-color: var(--ancient-color); +} + +.translate-empty-custom { + margin-top: 2px; + opacity: 0.72; + font-size: 0.8rem; +} + .transform-buttons { display: flex; flex-wrap: wrap; @@ -1565,10 +1940,6 @@ h1, h2, h3, h4, h5 { display: flex; } -#category-randomizer .transform-buttons .transform-button-group { - width: 100%; -} - #category-randomizer .transform-buttons .transform-button { width: 100%; } @@ -1656,29 +2027,37 @@ h1, h2, h3, h4, h5 { border-radius: 3px; } -/* Copy History Panel */ -.copy-history-panel { +/* Slide-out sidebars — one width on desktop; full width on small screens (see 768px media) */ +.app-sidebar { position: fixed; - right: -100%; top: 0; - width: 380px; + right: 0; + width: var(--sidebar-width); + max-width: min(100%, 90vw); height: 100vh; background-color: var(--secondary-bg); border-left: 1px solid var(--input-border); - z-index: 100; - box-shadow: -5px 0 15px rgba(0, 0, 0, 0.3); - transition: right 0.3s ease-in-out; + box-shadow: var(--sidebar-edge-shadow); display: flex; flex-direction: column; padding: 0; overflow: hidden; + transform: translateX(100%); + transition: transform 0.3s ease-in-out; + z-index: 100; } -.copy-history-panel.active { - right: 0; +.app-sidebar.active { + transform: translateX(0); } -.copy-history-header { +/* Advanced settings above other slide-outs when stacked */ +.unicode-options-panel { + z-index: 200; +} + +/* Sidebar header + actions (copy history, glitch, end sequences, advanced settings) */ +.app-sidebar-header { display: flex; justify-content: space-between; align-items: center; @@ -1687,20 +2066,35 @@ h1, h2, h3, h4, h5 { background-color: var(--button-bg); } -.copy-history-header h3 { +.app-sidebar-header h3 { font-size: 1.2rem; margin: 0; color: var(--accent-color); } -.copy-history-header .header-actions { +.end-sequence-header h3 { + color: #e85d4c; +} + +.unicode-panel-header { + position: relative; + z-index: 300; + pointer-events: auto; + touch-action: manipulation; +} + +.unicode-panel-header h3 { + font-size: 1.2rem; +} + +.app-sidebar-header .header-actions { display: flex; gap: 10px; align-items: center; } -.copy-history-header .clear-history-button, -.copy-history-header .close-button { +.app-sidebar-header .clear-history-button, +.app-sidebar-header .close-button { background: none; border: none; color: var(--text-color); @@ -1710,21 +2104,333 @@ h1, h2, h3, h4, h5 { transition: color 0.2s; } -.copy-history-header .clear-history-button:hover, -.copy-history-header .close-button:hover { +.app-sidebar-header .clear-history-button:hover, +.app-sidebar-header .close-button:hover { color: var(--accent-color); } -.copy-history-header .clear-history-button:hover { +.app-sidebar-header .clear-history-button:hover { color: #ff6b6b; } -.copy-history-content { +.end-sequence-header .close-button:hover { + color: #e85d4c; +} + +/* Scrollable body */ +.app-sidebar-body { flex: 1; overflow-y: auto; padding: 15px; } +.glitch-token-content, +.end-sequence-content { + display: flex; + flex-direction: column; +} + +.glitch-token-filters { + margin-bottom: 15px; + padding-bottom: 15px; + border-bottom: 1px solid var(--input-border); +} + +.filter-group { + margin-bottom: 12px; +} + +.filter-group:last-child { + margin-bottom: 0; +} + +.filter-group label { + display: block; + margin-bottom: 6px; + font-size: 0.9rem; + color: var(--text-color); + font-weight: 500; +} + +.filter-group select, +.filter-group input { + width: 100%; + padding: 8px; + background-color: var(--input-bg); + border: 1px solid var(--input-border); + border-radius: 4px; + color: var(--text-color); + font-size: 0.9rem; +} + +.filter-group select:focus, +.filter-group input:focus { + outline: none; + border-color: var(--accent-color); +} + +.glitch-token-list { + flex: 1; + overflow-y: auto; +} + +.no-tokens { + padding: 20px; + text-align: center; + color: var(--text-color); + opacity: 0.7; +} + +.token-cards { + display: flex; + flex-direction: column; + gap: 12px; +} + +.token-card { + background-color: var(--input-bg); + border: 1px solid var(--input-border); + border-radius: 4px; + padding: 12px; + transition: all 0.2s ease; +} + +.token-card:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +/* End sequences sidebar */ +.end-sequence-lede { + font-size: 0.9rem; + color: var(--text-color); + opacity: 0.9; + margin: 0 0 16px; + line-height: 1.45; +} + +.endsequence-category { + margin-bottom: 20px; +} + +.endsequence-category h4 { + font-size: 0.95rem; + margin: 0 0 10px; + color: #e85d4c; + border-bottom: 1px solid var(--input-border); + padding-bottom: 6px; +} + +.endsequence-items { + display: flex; + flex-direction: column; + gap: 8px; +} + +button.endsequence-item { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 10px; + width: 100%; + margin: 0; + padding: 8px 10px; + text-align: left; + font: inherit; + color: inherit; + cursor: pointer; + background: var(--input-bg); + border: 1px solid var(--input-border); + border-radius: 4px; + transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease; +} + +button.endsequence-item:hover { + background: var(--button-bg); + border-color: rgba(232, 93, 76, 0.45); +} + +button.endsequence-item:focus { + outline: none; +} + +button.endsequence-item:focus-visible { + outline: 2px solid #e85d4c; + outline-offset: 2px; +} + +.endsequence-label { + flex: 1; + word-break: break-word; + white-space: pre-wrap; + font-size: 0.85rem; + pointer-events: none; +} + +.endsequence-copy-affordance { + flex-shrink: 0; + display: flex; + align-items: center; + padding: 2px 0 0 4px; + opacity: 0.55; + color: #e85d4c; + pointer-events: none; +} + +button.endsequence-item:hover .endsequence-copy-affordance { + opacity: 0.95; +} + +/* Anti-Classifier tool */ +.anticlassifier-section .ac-lede { + font-size: 0.9rem; + color: var(--text-muted); + margin: 8px 0 0; + padding-left: 14px; + line-height: 1.45; +} + +.ac-response { + white-space: pre-wrap; + word-break: break-word; + font-family: inherit; + font-size: 0.9rem; + margin: 0; + padding: 12px; + background: var(--input-bg); + border: 1px solid var(--input-border); + border-radius: 4px; + max-height: 60vh; + overflow-y: auto; +} + +.ac-output-wrap { + margin-top: 16px; +} + +.token-card-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; +} + +.token-text { + font-family: 'Fira Code', monospace; + font-size: 1rem; + color: var(--text-color); + word-break: break-all; + flex: 1; + margin-right: 10px; +} + +.copy-token-button { + background: var(--button-bg); + border: 1px solid var(--input-border); + border-radius: 4px; + color: var(--text-color); + cursor: pointer; + padding: 6px 10px; + font-size: 0.9rem; + transition: all 0.2s; + flex-shrink: 0; +} + +.copy-token-button:hover { + background-color: var(--accent-color); + color: var(--button-bg); + border-color: var(--accent-color); +} + +.token-card-body { + display: flex; + flex-direction: column; + gap: 6px; +} + +.token-badge { + display: inline-block; + padding: 4px 8px; + border-radius: 4px; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + width: fit-content; +} + +.badge-unspeakable { + background-color: rgba(255, 107, 107, 0.2); + color: #ff6b6b; + border: 1px solid #ff6b6b; +} + +.badge-polysemantic { + background-color: rgba(255, 193, 7, 0.2); + color: #ffc107; + border: 1px solid #ffc107; +} + +.badge-glitched_spelling { + background-color: rgba(156, 39, 176, 0.2); + color: #9c27b0; + border: 1px solid #9c27b0; +} + +.badge-context_corruptor { + background-color: rgba(244, 67, 54, 0.2); + color: #f44336; + border: 1px solid #f44336; +} + +.badge-loop_inducer { + background-color: rgba(255, 0, 0, 0.3); + color: #ff0000; + border: 1px solid #ff0000; + font-weight: 700; +} + +.badge-identity_disruptor { + background-color: rgba(255, 152, 0, 0.2); + color: #ff9800; + border: 1px solid #ff9800; +} + +.badge-fragment { + background-color: rgba(158, 158, 158, 0.2); + color: #9e9e9e; + border: 1px solid #9e9e9e; +} + +.badge-unreachable { + background-color: rgba(96, 125, 139, 0.2); + color: #607d8b; + border: 1px solid #607d8b; +} + +.token-id, +.token-origin, +.token-output, +.token-note { + font-size: 0.85rem; + color: var(--text-muted); + line-height: 1.4; +} + +.token-id { + font-family: 'Fira Code', monospace; +} + +.token-output { + font-style: italic; +} + +.token-note { + margin-top: 4px; + padding-top: 6px; + border-top: 1px solid var(--input-border); + font-size: 0.8rem; +} + .no-history { padding: 20px; text-align: center; @@ -1926,7 +2632,7 @@ h1, h2, h3, h4, h5 { background: var(--button-bg); color: var(--text-color); transition: all 0.2s ease; - overflow: hidden; + overflow: visible; min-height: 70px; } @@ -2156,7 +2862,7 @@ h1, h2, h3, h4, h5 { opacity: 0.5; transition: all 0.2s ease; cursor: pointer; - z-index: 10; + z-index: 12; color: var(--text-color); } @@ -2176,6 +2882,208 @@ h1, h2, h3, h4, h5 { color: #ffed4e; } +/* Per-transform options (gear) */ +.transform-options-gear { + position: absolute; + left: 8px; + bottom: 8px; + font-size: 0.85rem; + opacity: 0.75; + transition: opacity 0.2s ease, transform 0.2s ease, color 0.2s ease; + cursor: pointer; + z-index: 12; + color: var(--accent-color); +} + +.transform-options-gear:hover { + opacity: 1; + color: var(--accent-color); + transform: scale(1.15); +} + +body.transform-options-modal-open { + overflow: hidden; +} + +.transform-options-backdrop { + position: fixed; + inset: 0; + z-index: 12000; + display: flex; + align-items: flex-end; + justify-content: center; + padding: 0; + background: rgba(0, 0, 0, 0.55); + -webkit-backdrop-filter: blur(2px); + backdrop-filter: blur(2px); +} + +@media (min-width: 600px) { + .transform-options-backdrop { + align-items: center; + padding: 16px; + } +} + +.transform-options-panel { + width: 100%; + max-width: 420px; + max-height: min(88vh, 640px); + display: flex; + flex-direction: column; + background: var(--main-bg-color); + color: var(--text-color); + border: 1px solid var(--input-border); + border-radius: 12px 12px 0 0; + box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.35); + overflow: hidden; +} + +@media (min-width: 600px) { + .transform-options-panel { + border-radius: 12px; + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4); + } +} + +.transform-options-panel-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 14px 16px; + border-bottom: 1px solid var(--input-border); + flex-shrink: 0; +} + +.transform-options-panel-header h3 { + margin: 0; + font-size: 1.05rem; + font-weight: 600; +} + +.transform-options-close { + flex-shrink: 0; + width: 40px; + height: 40px; + border: none; + border-radius: 8px; + background: transparent; + color: var(--text-color); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.1rem; +} + +.transform-options-close:hover { + background: var(--button-hover-bg); +} + +.transform-options-panel-body { + padding: 12px 16px 8px; + overflow-y: auto; + flex: 1; + -webkit-overflow-scrolling: touch; +} + +.transform-options-field { + margin-bottom: 14px; +} + +.transform-options-field label { + display: block; + margin-bottom: 6px; + font-size: 0.85rem; + font-weight: 500; + color: var(--text-color); +} + +.transform-options-checkbox { + width: 22px; + height: 22px; + min-width: 22px; + min-height: 22px; + cursor: pointer; + accent-color: var(--accent-color); +} + +.transform-options-select { + width: 100%; + max-width: 100%; + padding: 12px 14px; + font-size: 1rem; + border-radius: 8px; + border: 1px solid var(--input-border); + background: var(--button-bg); + color: var(--text-color); + min-height: 48px; +} + +.transform-options-text, +.transform-options-number { + width: 100%; + box-sizing: border-box; + padding: 12px 14px; + font-size: 1rem; + border-radius: 8px; + border: 1px solid var(--input-border); + background: var(--button-bg); + color: var(--text-color); + min-height: 48px; +} + +.transform-options-number { + -moz-appearance: textfield; + appearance: textfield; +} + +.transform-options-number::-webkit-outer-spin-button, +.transform-options-number::-webkit-inner-spin-button { + -webkit-appearance: none; + appearance: none; + margin: 0; +} + +.transform-options-panel-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: flex-end; + padding: 12px 16px 16px; + padding-bottom: max(16px, env(safe-area-inset-bottom)); + border-top: 1px solid var(--input-border); + flex-shrink: 0; +} + +.transform-options-btn { + min-height: 44px; + min-width: 88px; + padding: 10px 16px; + border-radius: 8px; + font-size: 0.95rem; + font-weight: 500; + cursor: pointer; + border: 1px solid var(--input-border); + background: var(--button-bg); + color: var(--text-color); +} + +.transform-options-btn-primary { + background: var(--accent-color); + border-color: var(--accent-color); + color: var(--main-bg-color); +} + +.transform-options-btn-primary:hover { + filter: brightness(1.08); +} + +.transform-options-btn-secondary:hover { + background: var(--button-hover-bg); +} + .favorites-section { border: 2px dashed #ffd700; background: rgba(255, 215, 0, 0.05); @@ -2186,10 +3094,6 @@ h1, h2, h3, h4, h5 { border-left-color: #ffd700; } -.favorites-section .transform-buttons .transform-button-group { - width: 100%; -} - /* Output section */ .output-section { display: flex; @@ -2527,50 +3431,18 @@ h1, h2, h3, h4, h5 { } -/* Global Unicode options panel (subtle, like copy history) */ -.unicode-options-panel { - position: fixed; - right: -360px; - top: 0; - width: 340px; - height: 100vh; - background: var(--secondary-bg); - border-left: 1px solid var(--input-border); - z-index: 200; - box-shadow: -5px 0 15px rgba(0,0,0,0.3); - transition: right 0.3s ease-in-out; - display: flex; - flex-direction: column; -} - -.unicode-options-panel.active { right: 0; } - -.unicode-panel-header { - padding: 12px; - border-bottom: 1px solid var(--input-border); +/* Unicode / Advanced Settings: shell + header close (touch-friendly) */ +.unicode-panel-header .close-button { + background: transparent; + border: none; + color: var(--text-color); + cursor: pointer; + padding: 8px; + min-width: 44px; + min-height: 44px; display: flex; align-items: center; - justify-content: space-between; - position: relative; - z-index: 300; - pointer-events: auto; - touch-action: manipulation; -} - -.unicode-panel-header h3 { margin: 0; color: var(--accent-color); font-size: 1rem; } - -.unicode-panel-content { padding: 12px; overflow-y: auto; } -.unicode-panel-header .close-button { - background: transparent; - border: none; - color: var(--text-color); - cursor: pointer; - padding: 8px; - min-width: 44px; - min-height: 44px; - display: flex; - align-items: center; - justify-content: center; + justify-content: center; font-size: 1.2rem; transition: all 0.2s ease; border-radius: 4px; @@ -2701,35 +3573,109 @@ html { gap: 12px; align-items: end; } +/* Range sliders — use in .slider-block (PromptCraft, Anti-Classifier, Tokenade) */ .slider-block { - background: var(--main-bg-color); + background: var(--input-bg); border: 1px solid var(--input-border); border-radius: 6px; - padding: 8px; + padding: 10px 12px; display: flex; flex-direction: column; + gap: 6px; + font-size: 0.8rem; + font-weight: 600; + letter-spacing: 0.02em; + color: var(--text-muted); } -.hacker-slider { + +.options-grid label.slider-block { + gap: 6px; +} + +.slider-block input[type="range"] { + -webkit-appearance: none; + appearance: none; width: 100%; - appearance: none; - height: 4px; - background: linear-gradient(90deg, rgba(100,181,246,.8), rgba(66,165,245,.4)); + height: 6px; + margin: 4px 0 2px; + background: transparent; + cursor: pointer; + border: none; outline: none; - border-radius: 3px; } -.slider-block .hacker-slider { margin-top: 6px; margin-bottom: 4px; } -.hacker-slider::-webkit-slider-thumb { + +.slider-block input[type="range"]::-webkit-slider-runnable-track { + height: 6px; + border-radius: 4px; + background: linear-gradient( + 90deg, + rgba(var(--accent-color-rgb), 0.42) 0%, + rgba(var(--accent-color-rgb), 0.1) 100% + ); + border: 1px solid var(--input-border); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); +} + +.slider-block input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; appearance: none; + width: 16px; + height: 16px; + margin-top: -5px; + background: var(--accent-color); + border-radius: 50%; + border: 2px solid var(--secondary-bg); + box-shadow: + 0 0 10px rgba(var(--accent-color-rgb), 0.45), + 0 1px 3px rgba(0, 0, 0, 0.35); + cursor: pointer; +} + +.slider-block input[type="range"]:focus-visible::-webkit-slider-thumb { + box-shadow: + 0 0 0 3px rgba(var(--accent-color-rgb), 0.35), + 0 0 10px rgba(var(--accent-color-rgb), 0.45), + 0 1px 3px rgba(0, 0, 0, 0.35); +} + +.slider-block input[type="range"]::-moz-range-track { + height: 6px; + border-radius: 4px; + background: linear-gradient( + 90deg, + rgba(var(--accent-color-rgb), 0.42) 0%, + rgba(var(--accent-color-rgb), 0.1) 100% + ); + border: 1px solid var(--input-border); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); +} + +.slider-block input[type="range"]::-moz-range-thumb { width: 14px; height: 14px; background: var(--accent-color); border-radius: 50%; - box-shadow: 0 0 8px rgba(100,181,246,.6); + border: 2px solid var(--secondary-bg); + box-shadow: + 0 0 10px rgba(var(--accent-color-rgb), 0.45), + 0 1px 3px rgba(0, 0, 0, 0.35); + cursor: pointer; } + +.slider-block input[type="range"]:focus-visible::-moz-range-thumb { + box-shadow: + 0 0 0 3px rgba(var(--accent-color-rgb), 0.35), + 0 0 10px rgba(var(--accent-color-rgb), 0.45), + 0 1px 3px rgba(0, 0, 0, 0.35); +} + .slider-value { - display: inline-block; - margin-left: 6px; + align-self: flex-end; + margin-top: 2px; font-family: 'Fira Code', monospace; + font-size: 0.85rem; + font-weight: 600; + font-variant-numeric: tabular-nums; color: var(--accent-color); } .segmented { @@ -2852,10 +3798,6 @@ html { /* Reduce extra whitespace at bottom of tab cards */ .tab-content .transform-layout > *:last-child { margin-bottom: 0; } -.transform-layout { - position: relative; -} - /* Keep the transform input visible while scrolling */ .transform-layout .input-section { position: sticky; @@ -2866,16 +3808,452 @@ html { box-shadow: 0 2px 8px rgba(0,0,0,0.15); } -/* Mutation Lab actions */ -.mutation-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 10px 0 12px 0; } -.mutation-actions .action-button, .mutation-actions .transform-button { white-space: nowrap; } -.mutation-actions .action-button.copy { border-color: #1976d2; color: #90caf9; } -.mutation-actions .action-button.copy:hover { color: #bbdefb; box-shadow: 0 0 0 1px rgba(144,202,249,.2) inset, 0 0 14px rgba(144,202,249,.18); } -.mutation-actions .action-button.download { border-color: #2e7d32; color: #69f0ae; } -.mutation-actions .action-button.download:hover { color: #b9f6ca; box-shadow: 0 0 0 1px rgba(105,240,174,.2) inset, 0 0 14px rgba(105,240,174,.18); } +/* Tool action toolbar — primary generate / copy / download rows */ +.tool-toolbar { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: center; + margin: 10px 0 12px 0; +} -/* Message Splitter Styles */ -.encapsulation-section { +.tool-toolbar .action-button, +.tool-toolbar .transform-button { + white-space: nowrap; +} + +.tool-toolbar .action-button.copy { + border-color: #1976d2; + color: #90caf9; +} + +.tool-toolbar .action-button.copy:hover { + color: #bbdefb; + box-shadow: 0 0 0 1px rgba(144,202,249,.2) inset, 0 0 14px rgba(144,202,249,.18); +} + +.tool-toolbar .action-button.download { + border-color: #2e7d32; + color: #69f0ae; +} + +.tool-toolbar .action-button.download:hover { + color: #b9f6ca; + box-shadow: 0 0 0 1px rgba(105,240,174,.2) inset, 0 0 14px rgba(105,240,174,.18); +} + +/* Primary “generate” actions — not transform-grid category tiles */ +.tool-toolbar .transform-button.tool-primary-btn { + flex: 1; + flex-direction: row; + align-items: center; + justify-content: center; + width: auto; + min-width: 200px; + min-height: 44px; + height: auto; + padding: 10px 20px; + gap: 10px; + background: linear-gradient(135deg, var(--accent-color), #42a5f5); + color: var(--main-bg-color); + border: 1px solid var(--accent-color); + font-weight: 600; +} + +.tool-toolbar .transform-button.tool-primary-btn:before, +.tool-toolbar .transform-button.tool-primary-btn:after { + display: none; +} + +.tool-toolbar .transform-button.tool-primary-btn i { + opacity: 0.95; +} + +.tool-toolbar .transform-button.tool-primary-btn:hover:not(:disabled) { + background: linear-gradient(135deg, var(--accent-color), #42a5f5); + border-color: var(--accent-color); + color: var(--main-bg-color); + filter: brightness(1.08); + box-shadow: 0 4px 12px rgba(var(--accent-color-rgb), 0.35); + transform: translateY(-1px); +} + +.tool-toolbar .transform-button.tool-primary-btn:disabled { + opacity: 0.65; + cursor: wait; + filter: none; +} + +/* Bijection / PromptCraft / Anti-Classifier — shared card shell + section chrome */ +.bijection-section.transform-section, +.promptcraft-section.transform-section, +.anticlassifier-section.transform-section { + background: var(--secondary-bg); + border: 1px solid var(--input-border); + border-radius: 8px; + padding: 16px; + box-shadow: var(--panel-shadow-soft); +} + +.bijection-section .section-header h3, +.promptcraft-section .section-header h3, +.anticlassifier-section .section-header h3 { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; + margin-bottom: 4px; + border-left: 4px solid var(--accent-color); + padding-left: 10px; +} + +.bijection-section .section-header h3 small, +.promptcraft-section .section-header h3 small, +.anticlassifier-section .section-header h3 small { + font-size: 0.75rem; + font-weight: 400; + color: var(--text-muted); + padding: 2px 8px; + border-radius: 999px; + border: 1px solid var(--input-border); + background: var(--main-bg-color); +} + +.bijection-section .input-section, +.promptcraft-section .input-section, +.anticlassifier-section .input-section { + position: static; + top: auto; + z-index: auto; + background: var(--main-bg-color); + border: 1px solid var(--input-border); + border-radius: 6px; + margin-bottom: 12px; + box-shadow: none; +} + +.bijection-section .bj-lede { + font-size: 0.9rem; + color: var(--text-muted); + margin: 8px 0 0; + padding-left: 14px; + line-height: 1.45; +} + +.bijection-section .bj-lede a { + color: var(--accent-color); + text-decoration: underline; + text-underline-offset: 2px; +} + +.bijection-section .bij-options.options-grid { + margin-top: 0; + margin-bottom: 8px; +} + +.bijection-section .bij-toggles.options-grid { + margin-top: 0; + margin-bottom: 12px; +} + +.bijection-section .bj-count { + font-size: 0.75rem; + font-weight: 600; + color: var(--accent-color); + font-family: 'Courier New', monospace; + margin-left: 4px; +} + +.bijection-section .bj-mapping-panel { + margin: 16px 0 0; + padding: 12px; + border-radius: 6px; + border: 1px solid var(--input-border); + background: var(--main-bg-color); +} + +.bijection-section .bj-mapping-head { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 10px; +} + +.bijection-section .bj-mapping-head h4 { + margin: 0; + font-size: 0.95rem; + display: flex; + align-items: center; + gap: 6px; + color: var(--text-color); +} + +.bijection-section .bj-mapping-grid { + display: flex; + flex-wrap: wrap; + gap: 8px; + max-height: 200px; + overflow-y: auto; + padding: 4px 0; +} + +.bijection-section .bj-map-chip { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 10px; + border-radius: 6px; + border: 1px solid var(--input-border); + background: var(--secondary-bg); + font-size: 0.85rem; +} + +.bijection-section .bj-map-key { font-family: ui-monospace, monospace; font-weight: 600; } +.bijection-section .bj-map-val { font-family: ui-monospace, monospace; opacity: 0.95; } +.bijection-section .bj-map-arrow { opacity: 0.45; font-size: 0.8rem; } + +.bijection-section .bj-output-title { + margin: 16px 0 10px; + font-size: 0.95rem; + display: flex; + align-items: center; + gap: 6px; + color: var(--text-color); +} + +.bijection-section .bj-results { + display: flex; + flex-direction: column; + gap: 12px; +} + +.bijection-section .bj-result-card, +.pc-result-card { + background: var(--main-bg-color); + border: 1px solid var(--input-border); + border-radius: 6px; + padding: 12px; +} + +.bijection-section .bj-result-header { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + margin-bottom: 8px; + padding-bottom: 8px; + border-bottom: 1px solid var(--input-border); +} + +.bijection-section .bj-result-num, +.pc-result-num { + font-size: 0.75rem; + font-weight: 600; + color: var(--accent-color); + font-family: 'Courier New', monospace; +} + +.bijection-section .bj-result-meta { + flex: 1; + font-size: 0.75rem; + color: var(--text-muted); + min-width: 0; +} + +.bijection-section .bj-copy-btn { + margin-left: auto; + background: transparent; + border: 1px solid var(--input-border); + color: var(--text-muted); + border-radius: 6px; + padding: 6px 10px; + cursor: pointer; + transition: border-color 0.15s ease, color 0.15s ease; +} + +.bijection-section .bj-copy-btn:hover { + border-color: var(--accent-color); + color: var(--accent-color); +} + +.bijection-section .bj-prompt-text { + width: 100%; + min-height: 120px; + font-family: 'Fira Code', ui-monospace, monospace; + font-size: 0.82rem; + line-height: 1.45; + background: var(--input-bg); + border: 1px solid var(--input-border); + border-radius: 4px; + color: var(--text-color); + padding: 8px; + resize: vertical; +} + +.bijection-section .bj-encoded { + margin: 8px 0 0; + font-size: 0.82rem; + word-break: break-word; + color: var(--text-muted); +} + +.pc-controls { + margin-top: 4px; +} + +.pc-strategies { + margin-bottom: 12px; +} + +.pc-label { + display: block; + font-size: 0.72rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; + color: var(--text-muted); + margin-bottom: 8px; +} + +.pc-strategy-grid { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.pc-strategy-btn { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 6px; + min-width: 96px; + flex: 1 1 calc(33.333% - 8px); + max-width: calc(33.333% - 6px); + padding: 10px 8px; + font-size: 0.75rem; + font-weight: 500; + text-align: center; + line-height: 1.2; + color: var(--text-color); + background-color: var(--button-bg); + border: 1px solid var(--input-border); + border-radius: 6px; + cursor: pointer; + transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease; +} + +.pc-strategy-btn i { + font-size: 1rem; + opacity: 0.9; +} + +.pc-strategy-btn:hover:not(.active) { + background-color: var(--button-hover-bg); + border-color: var(--accent-color); + color: var(--accent-color); +} + +.pc-strategy-btn:hover:not(.active) i { + color: var(--accent-color); +} + +.pc-strategy-btn.active { + background-color: var(--accent-color); + color: var(--main-bg-color); + border-color: var(--accent-color); + font-weight: 600; + box-shadow: 0 2px 8px rgba(var(--accent-color-rgb), 0.35); +} + +.pc-strategy-btn.active i { + color: var(--main-bg-color); + opacity: 1; +} + +.pc-strategy-btn:focus { + outline: none; + box-shadow: var(--focus-shadow); +} + +.pc-strategy-btn.active:focus { + box-shadow: 0 0 0 2px rgba(var(--accent-color-rgb), 0.5), 0 2px 8px rgba(var(--accent-color-rgb), 0.35); +} + +.pc-custom-instruction { + margin-bottom: 12px; +} + +.pc-custom-instruction textarea { + width: 100%; + margin-top: 6px; +} + +.pc-options.options-grid { + margin-top: 4px; +} + +.pc-results { + display: flex; + flex-direction: column; + gap: 12px; + margin-top: 8px; +} + +.pc-result-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 8px; + padding-bottom: 8px; + border-bottom: 1px solid var(--input-border); +} + +.pc-result-text { + font-size: 0.9rem; + line-height: 1.5; + white-space: pre-wrap; + word-break: break-word; + color: var(--text-color); +} + +.pc-empty-state { + text-align: center; + padding: 24px 16px; + color: var(--text-muted); + border: 1px dashed var(--input-border); + border-radius: 8px; + margin-top: 12px; + background: rgba(0, 0, 0, 0.15); +} + +.pc-empty-state i { + font-size: 2rem; + margin-bottom: 8px; + opacity: 0.5; + color: var(--accent-color); +} + +@media (max-width: 768px) { + .pc-strategy-btn { + flex: 1 1 calc(50% - 4px); + max-width: calc(50% - 4px); + } +} + +@media (max-width: 480px) { + .pc-strategy-btn { + flex: 1 1 100%; + max-width: 100%; + } +} + +/* Message Splitter — encapsulation + JSON/XML field panels share chrome */ +.encapsulation-section, +.json-fields-section, +.xml-attributes-section { margin-top: 16px; padding: 16px; background: var(--main-bg-color); @@ -2883,11 +4261,15 @@ html { border-radius: 8px; } -.encapsulation-section .section-header { +.encapsulation-section .section-header, +.json-fields-section .section-header, +.xml-attributes-section .section-header { margin-bottom: 16px; } -.encapsulation-section .section-header h4 { +.encapsulation-section .section-header h4, +.json-fields-section .section-header h4, +.xml-attributes-section .section-header h4 { margin-bottom: 4px; margin-top: 0; color: var(--accent-color); @@ -2897,7 +4279,9 @@ html { gap: 8px; } -.encapsulation-section .section-header p { +.encapsulation-section .section-header p, +.json-fields-section .section-header p, +.xml-attributes-section .section-header p { margin: 0; color: var(--text-muted); font-size: 0.9em; @@ -2908,6 +4292,56 @@ html { flex-wrap: wrap; align-items: center; gap: 8px; +} + +.field-row { + display: flex; + gap: 8px; + margin-bottom: 8px; + align-items: center; +} + +.field-row input { + flex: 1; + padding: 8px; + background-color: var(--input-bg); + border: 1px solid var(--input-border); + border-radius: 4px; + color: var(--text-color); + font-size: 0.9rem; +} + +.field-row input:focus { + outline: none; + border-color: var(--accent-color); +} + +.remove-field-button, +.add-field-button { + background-color: var(--button-bg); + border: 1px solid var(--input-border); + border-radius: 4px; + color: var(--text-color); + cursor: pointer; + padding: 8px 12px; + font-size: 0.9rem; + transition: all 0.2s; + white-space: nowrap; +} + +.remove-field-button:hover { + background-color: #ff6b6b; + border-color: #ff6b6b; + color: white; +} + +.add-field-button:hover { + background-color: var(--accent-color); + border-color: var(--accent-color); + color: var(--button-bg); +} + +.add-field-button { margin-top: 12px; } @@ -3224,15 +4658,6 @@ html { font-size: 0.9rem; } -/* Splitter-specific action button styling */ -.splitter-actions { - display: flex; - gap: 10px; - align-items: center; - flex-wrap: wrap; - margin: 16px 0 0 0; -} - .splitter-copy-option { margin-left: 0; } @@ -3307,6 +4732,11 @@ html { flex: 0 0 calc((100% - 32px) / 5); /* 5 columns: account for 4 gaps of 8px */ min-width: 0; } + + .translate-lang-grid-inline .translate-lang-btn { + flex: 0 0 calc((100% - 32px) / 5); + min-width: 0; + } } /* Tablets and below (768px) */ @@ -3334,12 +4764,11 @@ html { } .tab-buttons { - flex-direction: column; + display: none; } - .tab-buttons button { - width: 100%; - text-align: left; + .tab-tool-select { + display: block; } .section-title { @@ -3388,12 +4817,14 @@ html { margin: 4px 0; } - .splitter-actions { + .tool-toolbar { flex-direction: column; align-items: stretch; + gap: var(--spacing-sm); } - - .splitter-actions button { + + .tool-toolbar button, + .tool-toolbar .switch { width: 100%; } @@ -3407,6 +4838,30 @@ html { min-width: 0; max-width: calc(50% - 4px); } + + /* Translation (AI) language tiles: 2 columns on phones/tablets (grid is more reliable than flex here) */ + .translate-lang-grid.translate-lang-grid-inline { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; + } + + .translate-lang-grid-inline .translate-lang-btn { + flex: none; + width: 100%; + min-width: 0; + max-width: none; + white-space: normal; + } + + .app-sidebar { + width: 100%; + max-width: 100%; + } + + .unicode-options-panel { + z-index: 300; + } } /* Medium screens (900px) */ @@ -3456,12 +4911,6 @@ html { justify-content: center; } - /* Tab buttons remain stacked but with smaller padding */ - .tab-buttons button { - padding: var(--spacing-sm) var(--spacing-sm); - font-size: 13px; - } - /* Transform buttons flex more compact - 2 columns on mobile */ .transform-buttons { gap: var(--spacing-xs); @@ -3472,6 +4921,8 @@ html { min-width: 0; max-width: calc(50% - 2px); } + + /* Translation tiles: same 2-col grid as 768px (inherit from above) */ /* Options grid single column on very small screens */ .options-grid { @@ -3486,17 +4937,6 @@ html { gap: var(--spacing-sm); } - /* Unicode options panel full width */ - .unicode-options-panel { - width: 100%; - right: -100%; - z-index: 300; /* Ensure it's above other content on mobile */ - } - - .unicode-options-panel.active { - right: 0; - } - .unicode-panel-header .close-button { min-width: 48px; min-height: 48px; @@ -3559,28 +4999,6 @@ html { font-size: 0.85rem; } - /* Mutation actions stack */ - .mutation-actions { - flex-direction: column; - align-items: stretch; - } - - .mutation-actions button { - width: 100%; - } - - /* Splitter actions stack */ - .splitter-actions { - flex-direction: column; - align-items: stretch; - gap: var(--spacing-sm); - } - - .splitter-actions button, - .splitter-actions .switch { - width: 100%; - } - /* Transform button preview text */ .transform-preview { font-size: 0.7rem; @@ -3690,16 +5108,6 @@ html { padding: 3px var(--spacing-xs); } - /* Copy history panel full width */ - .copy-history-panel { - width: 100%; - right: -100%; - } - - .copy-history-panel.active { - right: 0; - } - /* Transform chain items stack vertically */ .transform-chain-item select { min-width: 100%; diff --git a/docs/TOOL-SYSTEM.md b/docs/TOOL-SYSTEM.md index f270476..db9dd2f 100644 --- a/docs/TOOL-SYSTEM.md +++ b/docs/TOOL-SYSTEM.md @@ -59,8 +59,20 @@ class MyTool extends Tool { ```html