Files
P4RS3LT0NGV3/index.html
T

1007 lines
62 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Parseltongue 2.0 - LLM Payload Crafter</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/notification.css">
<!-- Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<!-- Font Awesome for icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head>
<body>
<div id="app" class="container">
<header>
<div class="logo">
<h1>🐉️︎︎︎︎︎︎︎️︎︎︎️︎︎︎️︎️️ P4RS3LT0NGV3</h1>
</div>
<div class="actions">
<button
@click="toggleCopyHistory"
class="history-button"
title="Show copy history"
aria-label="Show copy history"
>
<i class="fas fa-history"></i>
</button>
<button
@click="toggleTheme"
@keyup.d="toggleTheme"
class="theme-button"
title="Toggle dark mode (D)"
aria-label="Toggle dark mode"
>
<i class="fas" :class="isDarkTheme ? 'fa-moon' : 'fa-sun'"></i>
</button>
<a
href="https://github.com/elder-plinius/P4RS3LT0NGV3"
target="_blank"
class="github-button"
title="View source on GitHub"
aria-label="View source code on GitHub"
>
<i class="fab fa-github"></i>
</a>
<button
@click="toggleUnicodePanel"
class="history-button"
title="Advanced Unicode options"
aria-label="Advanced Unicode options"
>
<i class="fas fa-sliders-h"></i>
</button>
</div>
</header>
<div class="tabs">
<div class="tab-buttons">
<button
:class="{ active: activeTab === 'transforms' }"
@click="switchToTab('transforms')"
title="Transform text (T)"
>
<i class="fas fa-font"></i> Transform
</button>
<button
:class="{ active: activeTab === 'steganography' }"
@click="switchToTab('steganography')"
title="Hide text in emojis (H)"
>
<i class="fas fa-smile"></i> Emoji
</button>
<button
:class="{ active: activeTab === 'tokenade' }"
@click="switchToTab('tokenade')"
title="Tokenade Generator"
>
<i class="fas fa-bomb"></i> Tokenade
</button>
<button
:class="{ active: activeTab === 'tokenizer' }"
@click="switchToTab('tokenizer')"
title="Tokenizer visualization"
>
<i class="fas fa-layer-group"></i> Tokenizer
</button>
</div>
<!-- Steganography Tab -->
<div v-if="activeTab === 'steganography'" class="tab-content">
<div class="transform-layout">
<div class="input-section">
<textarea
id="steg-input"
v-model="emojiMessage"
placeholder="Enter text to hide..."
@input="autoEncode"
></textarea>
</div>
<!-- Emoji Library Section -->
<div class="emoji-library">
<!-- Emoji grid container - this MUST have id="emoji-grid-container" -->
<div id="emoji-grid-container" class="emoji-grid-container">
<!-- Dynamic content will be inserted here by JavaScript -->
<div class="emoji-grid">
<!-- Common emojis as fallback -->
<button class="emoji-button" onclick="app.selectEmoji('😀')">😀</button>
<button class="emoji-button" onclick="app.selectEmoji('😂')">😂</button>
<button class="emoji-button" onclick="app.selectEmoji('🥰')">🥰</button>
<button class="emoji-button" onclick="app.selectEmoji('😎')">😎</button>
<button class="emoji-button" onclick="app.selectEmoji('🤔')">🤔</button>
<button class="emoji-button" onclick="app.selectEmoji('👍')">👍</button>
<button class="emoji-button" onclick="app.selectEmoji('🎉')">🎉</button>
<button class="emoji-button" onclick="app.selectEmoji('🔥')">🔥</button>
<button class="emoji-button" onclick="app.selectEmoji('🚀')">🚀</button>
<button class="emoji-button" onclick="app.selectEmoji('🐍')">🐍</button>
</div>
</div>
<div class="emoji-library-footer" v-if="selectedEmoji">
<div class="selected-emoji-info">
<span class="selected-emoji">{{ selectedEmoji }}</span>
<span class="selected-emoji-label">Last selected</span>
</div>
</div>
</div>
<div class="output-section" v-if="encodedMessage">
<div class="output-heading">
<h4>
<i class="fas fa-check-circle"></i>
Encoded Message
<small v-if="selectedCarrier">using {{ selectedCarrier.name }}</small>
<small v-else-if="activeSteg === 'invisible'">using Invisible Text</small>
</h4>
</div>
<div class="output-container">
<textarea readonly v-model="encodedMessage"></textarea>
<button class="copy-button" @click="copyToClipboard(encodedMessage)" title="Copy to clipboard">
<i class="fas fa-copy"></i>
</button>
</div>
<div class="output-instructions">
<small><i class="fas fa-info-circle"></i> Copy this text and share it. Only people who know how to decode it will be able to read your message.</small>
</div>
</div>
<!-- Universal Decoder Section for Steganography Tab -->
<div class="decode-section">
<div class="section-header">
<h3>
<i class="fas fa-magic"></i> Universal Decoder
<small v-if="activeTransform">(Prioritizing {{ activeTransform.name }})</small>
</h3>
<p v-if="activeTransform && transformHasReverse(activeTransform)">
Paste encoded text to decode with {{ activeTransform.name }} or try other methods
</p>
<p v-else>Paste any encoded text to try all decoding methods at once</p>
</div>
<div class="input-container">
<textarea
id="universal-decode-input-steg"
v-model="universalDecodeInput"
placeholder="Paste encoded text to decode automatically..."
@input="runUniversalDecode"
></textarea>
<div class="decoded-message" v-if="universalDecodeResult">
<div class="decode-method">
<span>Decoded using: <strong>{{ universalDecodeResult.method }}</strong></span>
<span v-if="activeTransform && universalDecodeResult.method === activeTransform.name" class="decode-priority">(Priority Match)</span>
</div>
<div class="decode-result">{{ universalDecodeResult.text }}</div>
<div class="decode-actions">
<button class="copy-button" @click="copyToClipboard(universalDecodeResult.text)" title="Copy decoded text">
<i class="fas fa-copy"></i> Copy
</button>
<button class="use-as-input-button" v-if="universalDecodeResult.text" @click="transformInput = universalDecodeResult.text" title="Use this as input for transforms">
<i class="fas fa-arrow-up"></i> Use as Input
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Tokenizer Visualization Tab -->
<div v-if="activeTab === 'tokenizer'" class="tab-content">
<div class="transform-layout">
<div class="input-section">
<div class="section-header">
<h3><i class="fas fa-layer-group"></i> Tokenizer Visualization <small>{{ tokenizerEngine }}</small></h3>
<p>Paste text to see how different tokenizers segment it.</p>
</div>
<div class="options-grid" style="margin-bottom:8px;">
<label>
Engine
<select v-model="tokenizerEngine" @change="runTokenizer">
<option value="byte">UTF-8 bytes</option>
<option value="word">Naive words</option>
<option value="gpt3">Experimental: gpt-3-encoder (if available)</option>
</select>
</label>
</div>
<textarea
id="tokenizer-input"
v-model="tokenizerInput"
placeholder="Paste text to visualize tokens"
@input="runTokenizer"
></textarea>
</div>
<div class="output-section">
<div class="output-heading">
<h4>
<i class="fas fa-chart-bar"></i> Tokens
<small>{{ tokenizerTokens.length }} total · {{ tokenizerWordCount }} words · {{ tokenizerCharCount }} chars</small>
</h4>
</div>
<div class="token-tiles" v-if="tokenizerTokens.length" style="display:flex; flex-wrap:wrap; gap:6px;">
<div v-for="(tok, i) in tokenizerTokens" :key="i" class="token-chip" style="background:var(--button-bg); border:1px solid var(--input-border); padding:6px 8px; border-radius:6px; font-family:'Fira Code', monospace;">
<span style="opacity:.75; margin-right:6px;">{{ i }}</span>
<span>{{ tok.text }}</span>
<span v-if="tok.id !== undefined" style="opacity:.6; margin-left:6px;">#{{ tok.id }}</span>
</div>
</div>
<div class="output-instructions" v-else>
<small>Tokens will appear here.</small>
</div>
</div>
</div>
</div>
<!-- Tokenade Tab -->
<div v-if="activeTab === 'tokenade'" class="tab-content">
<div class="transform-layout">
<div class="token-bomb-section">
<div class="section-header">
<h3>
<span title="High-density token payload builder">💥 Tokenade Generator</span>
<small>Craft dense token sequences with emojis and zero-width characters</small>
</h3>
</div>
<div class="output-instructions">
<small>
<strong>Disclaimer:</strong> These payloads can be disruptive to models, UIs, and tools. Use responsibly and avoid deploying in production or against systems without consent.
</small>
</div>
<div class="tokenade-presets">
<button class="transform-button" title="Very light density" @click="applyTokenadePreset('feather')">🪶 Featherweight</button>
<button class="transform-button" title="Light density" @click="applyTokenadePreset('light')">🍃 Lightweight</button>
<button class="transform-button" title="Balanced density" @click="applyTokenadePreset('middle')">🪨 Middleweight</button>
<button class="transform-button" title="High density" @click="applyTokenadePreset('heavy')">🗿 Heavyweight</button>
<button class="transform-button" title="Extreme density (use with care)" @click="applyTokenadePreset('super')">⚓ Super Heavyweight</button>
</div>
<div class="token-bomb-controls options-grid hacker-controls">
<label class="slider-block" title="Nesting levels; higher = more layers of grouping">
Depth (nesting)
<input class="hacker-slider" type="range" v-model.number="tbDepth" min="1" max="8" />
<span class="slider-value">{{ tbDepth }}</span>
</label>
<label class="slider-block" title="How many items per level; higher = wider structure">
Breadth per level
<input class="hacker-slider" type="range" v-model.number="tbBreadth" min="1" max="12" />
<span class="slider-value">{{ tbBreadth }}</span>
</label>
<label class="slider-block" title="How many times to repeat the whole block">
Repeats (blocks)
<input class="hacker-slider" type="range" v-model.number="tbRepeats" min="1" max="100" />
<span class="slider-value">{{ tbRepeats }}</span>
</label>
<div class="segmented" title="Invisible separator inserted between units">
<div class="segmented-label">Separator</div>
<button :class="{active: tbSeparator==='zwj'}" @click="tbSeparator='zwj'">ZWJ</button>
<button :class="{active: tbSeparator==='zwnj'}" @click="tbSeparator='zwnj'">ZWNJ</button>
<button :class="{active: tbSeparator==='zwsp'}" @click="tbSeparator='zwsp'">ZWSP</button>
<button :class="{active: tbSeparator==='none'}" @click="tbSeparator='none'">None</button>
</div>
<label class="switch" title="Adds VS16/VS15 after glyphs to increase token churn">
<input type="checkbox" v-model="tbIncludeVS" />
<span>Variation Selectors</span>
</label>
<label class="switch" title="Sprinkles random zero-width codepoints between segments">
<input type="checkbox" v-model="tbIncludeNoise" />
<span>Invisible Noise</span>
</label>
<label class="switch" title="Use random emojis instead of cycling a fixed set">
<input type="checkbox" v-model="tbRandomizeEmojis" />
<span>Randomize</span>
</label>
<label class="switch" title="Automatically copy result after generation">
<input type="checkbox" v-model="tbAutoCopy" />
<span>Auto-copy</span>
</label>
</div>
<div class="output-instructions">
<small>
Estimated length: {{ estimateTokenadeLength().toLocaleString() }} chars
</small>
</div>
<div class="tokenade-carrier-options options-grid">
<div class="carrier-quick-grid" v-if="tbSingleCarrier">
<small>Quick picks</small>
<div class="emoji-grid" style="grid-template-columns: repeat(10, 32px); grid-auto-rows: 32px; gap: 6px;">
<button class="emoji-button" v-for="em in quickCarrierEmojis" :key="'q-'+em" @click="tbCarrier = em" :title="'Use '+em">{{ em }}</button>
</div>
</div>
<label title="Condense payload into a single emoji carrier">
Single emoji carrier mode
<input type="checkbox" v-model="tbSingleCarrier" />
</label>
<label v-if="tbSingleCarrier" title="Choose the carrier emoji (quick list)">
Carrier
<select v-model="tbCarrier" @focus="setCarrierFromSelected">
<option v-for="em in carrierEmojiList" :key="em" :value="em">{{ em }}</option>
</select>
</label>
<label v-if="tbSingleCarrier" title="Advanced: use this symbol or string as the embedded payload for encoding">
Advanced: custom carrier text
<input type="text" v-model="tbCarrierManual" placeholder="e.g., ⚙️ or ::tag::" />
<small>When set, this overrides quick picks and dropdown.</small>
</label>
</div>
<div class="token-bomb-actions">
<button class="transform-button" @click="generateTokenBomb" title="Build the tokenade with current settings">
<i class="fas fa-hammer"></i> Generate Tokenade
</button>
<button class="copy-button" v-if="tokenBombOutput" @click="copyToClipboard(tokenBombOutput)">
<i class="fas fa-copy"></i> Copy
</button>
<div class="output-instructions" v-if="tokenBombOutput">
<small>
Length: {{ tokenBombOutput.length.toLocaleString() }} chars · Tip: Increasing depth/breadth grows size <em>multiplicatively</em>.
</small>
</div>
</div>
<div class="output-container" v-if="tokenBombOutput">
<textarea readonly v-model="tokenBombOutput" aria-label="Token bomb output"></textarea>
</div>
</div>
<!-- Text Payload Generator (simple) -->
<div class="transform-section">
<h4><i class="fas fa-font"></i> Text Payload Generator</h4>
<div class="options-grid">
<label>
Base text
<input type="text" v-model="tpBase" placeholder="Enter base snippet (e.g., hello)" />
</label>
<label>
Repeat count
<input type="number" v-model.number="tpRepeat" min="1" max="1000" />
</label>
<label>
Add combining marks
<input type="checkbox" v-model="tpCombining" />
</label>
<label>
Add zero-width spacing
<input type="checkbox" v-model="tpZW" />
</label>
</div>
<div class="token-bomb-actions">
<button class="transform-button" @click="generateTextPayload">
<i class="fas fa-hammer"></i> Generate Text Payload
</button>
<button class="copy-button" v-if="textPayload" @click="copyToClipboard(textPayload)">
<i class="fas fa-copy"></i> Copy
</button>
</div>
<div class="output-container" v-if="textPayload">
<textarea readonly v-model="textPayload" aria-label="Text payload output"></textarea>
</div>
</div>
</div>
</div>
<!-- Text Transforms Tab -->
<div v-if="activeTab === 'transforms'" class="tab-content">
<div class="transform-layout">
<div class="input-section">
<textarea
id="transform-input"
v-model="transformInput"
placeholder="Enter text to transform..."
@input="autoTransform"
></textarea>
</div>
<div class="transform-section">
<div class="transform-category-legend">
<div class="legend-title">Categories:</div>
<div class="legend-item transform-category-encoding" data-target="category-encoding">Encoding</div>
<div class="legend-item transform-category-cipher" data-target="category-cipher">Ciphers</div>
<div class="legend-item transform-category-visual" data-target="category-visual">Visual</div>
<div class="legend-item transform-category-format" data-target="category-format">Formatting</div>
<div class="legend-item transform-category-unicode" data-target="category-unicode">Unicode</div>
<div class="legend-item transform-category-special" data-target="category-special">Special</div>
<div class="legend-item transform-category-fantasy" data-target="category-fantasy">Fantasy</div>
<div class="legend-item transform-category-ancient" data-target="category-ancient">Ancient</div>
<div class="legend-item transform-category-technical" data-target="category-technical">Technical</div>
<div class="legend-item transform-category-randomizer" data-target="category-randomizer">🎲 Randomizer</div>
</div>
<div class="transform-categories">
<!-- Encoding Category -->
<div id="category-encoding" class="transform-category-section">
<h4 class="category-title transform-category-encoding">Encoding</h4>
<div class="transform-buttons">
<div v-for="transform in getTransformsByCategory('encoding')" :key="transform.name" class="transform-button-group">
<button
@click="applyTransform(transform, $event)"
class="transform-button transform-category-encoding"
:class="{ active: activeTransform === transform }"
:title="'Click to transform and copy: ' + transform.name"
>
{{ transform.name }}
<small class="transform-preview" v-if="transformInput">
{{ transform.preview(transformInput.slice(0, 10)) }}
</small>
<i class="fas fa-copy auto-copy-icon"></i>
</button>
<button
v-if="transformHasReverse(transform)"
@click="decodeWithTransform(transform)"
class="decode-button transform-category-encoding"
:title="'Click to decode using: ' + transform.name"
>
<i class="fas fa-undo"></i>
</button>
</div>
</div>
</div>
<!-- Cipher Category -->
<div id="category-cipher" class="transform-category-section">
<h4 class="category-title transform-category-cipher">Ciphers</h4>
<div class="transform-buttons">
<div v-for="transform in getTransformsByCategory('cipher')" :key="transform.name" class="transform-button-group">
<button
@click="applyTransform(transform, $event)"
class="transform-button transform-category-cipher"
:class="{ active: activeTransform === transform }"
:title="'Click to transform and copy: ' + transform.name"
>
{{ transform.name }}
<small class="transform-preview" v-if="transformInput">
{{ transform.preview(transformInput.slice(0, 10)) }}
</small>
<i class="fas fa-copy auto-copy-icon"></i>
</button>
<button
v-if="transformHasReverse(transform)"
@click="decodeWithTransform(transform)"
class="decode-button transform-category-cipher"
:title="'Click to decode using: ' + transform.name"
>
<i class="fas fa-undo"></i>
</button>
</div>
</div>
</div>
<!-- Visual Category -->
<div id="category-visual" class="transform-category-section">
<h4 class="category-title transform-category-visual">Visual</h4>
<div class="transform-buttons">
<div v-for="transform in getTransformsByCategory('visual')" :key="transform.name" class="transform-button-group">
<button
@click="applyTransform(transform, $event)"
class="transform-button transform-category-visual"
:class="{ active: activeTransform === transform }"
:title="'Click to transform and copy: ' + transform.name"
>
{{ transform.name }}
<small class="transform-preview" v-if="transformInput">
{{ transform.preview(transformInput.slice(0, 10)) }}
</small>
<i class="fas fa-copy auto-copy-icon"></i>
</button>
<button
v-if="transformHasReverse(transform)"
@click="decodeWithTransform(transform)"
class="decode-button transform-category-visual"
:title="'Click to decode using: ' + transform.name"
>
<i class="fas fa-undo"></i>
</button>
</div>
</div>
</div>
<!-- Format Category -->
<div id="category-format" class="transform-category-section">
<h4 class="category-title transform-category-format">Formatting</h4>
<div class="transform-buttons">
<div v-for="transform in getTransformsByCategory('format')" :key="transform.name" class="transform-button-group">
<button
@click="applyTransform(transform, $event)"
class="transform-button transform-category-format"
:class="{ active: activeTransform === transform }"
:title="'Click to transform and copy: ' + transform.name"
>
{{ transform.name }}
<small class="transform-preview" v-if="transformInput">
{{ transform.preview(transformInput.slice(0, 10)) }}
</small>
<i class="fas fa-copy auto-copy-icon"></i>
</button>
<button
v-if="transformHasReverse(transform)"
@click="decodeWithTransform(transform)"
class="decode-button transform-category-format"
:title="'Click to decode using: ' + transform.name"
>
<i class="fas fa-undo"></i>
</button>
</div>
</div>
</div>
<!-- Unicode Category -->
<div id="category-unicode" class="transform-category-section">
<h4 class="category-title transform-category-unicode">Unicode</h4>
<div class="transform-buttons">
<div v-for="transform in getTransformsByCategory('unicode')" :key="transform.name" class="transform-button-group">
<button
@click="applyTransform(transform, $event)"
class="transform-button transform-category-unicode"
:class="{ active: activeTransform === transform }"
:title="'Click to transform and copy: ' + transform.name"
>
{{ transform.name }}
<small class="transform-preview" v-if="transformInput">
{{ transform.preview(transformInput.slice(0, 10)) }}
</small>
<i class="fas fa-copy auto-copy-icon"></i>
</button>
<button
v-if="transformHasReverse(transform)"
@click="decodeWithTransform(transform)"
class="decode-button transform-category-unicode"
:title="'Click to decode using: ' + transform.name"
>
<i class="fas fa-undo"></i>
</button>
</div>
</div>
</div>
<!-- Special Category -->
<div id="category-special" class="transform-category-section">
<h4 class="category-title transform-category-special">Special</h4>
<div class="transform-buttons">
<div v-for="transform in getTransformsByCategory('special')" :key="transform.name" class="transform-button-group">
<button
@click="applyTransform(transform, $event)"
class="transform-button transform-category-special"
:class="{ active: activeTransform === transform }"
:title="'Click to transform and copy: ' + transform.name"
>
{{ transform.name }}
<small class="transform-preview" v-if="transformInput">
{{ transform.preview(transformInput.slice(0, 10)) }}
</small>
<i class="fas fa-copy auto-copy-icon"></i>
</button>
<button
v-if="transformHasReverse(transform)"
@click="decodeWithTransform(transform)"
class="decode-button transform-category-special"
:title="'Click to decode using: ' + transform.name"
>
<i class="fas fa-undo"></i>
</button>
</div>
</div>
</div>
<!-- Fantasy Category -->
<div id="category-fantasy" class="transform-category-section">
<h4 class="category-title transform-category-fantasy">Fantasy</h4>
<div class="transform-buttons">
<div v-for="transform in getTransformsByCategory('fantasy')" :key="transform.name" class="transform-button-group">
<button
@click="applyTransform(transform, $event)"
class="transform-button transform-category-fantasy"
:class="{ active: activeTransform === transform }"
:title="'Click to transform and copy: ' + transform.name"
>
{{ transform.name }}
<small class="transform-preview" v-if="transformInput">
{{ transform.preview(transformInput.slice(0, 10)) }}
</small>
<i class="fas fa-copy auto-copy-icon"></i>
</button>
<button
v-if="transformHasReverse(transform)"
@click="decodeWithTransform(transform)"
class="decode-button transform-category-fantasy"
:title="'Click to decode using: ' + transform.name"
>
<i class="fas fa-undo"></i>
</button>
</div>
</div>
</div>
<!-- Ancient Category -->
<div id="category-ancient" class="transform-category-section">
<h4 class="category-title transform-category-ancient">Ancient</h4>
<div class="transform-buttons">
<div v-for="transform in getTransformsByCategory('ancient')" :key="transform.name" class="transform-button-group">
<button
@click="applyTransform(transform, $event)"
class="transform-button transform-category-ancient"
:class="{ active: activeTransform === transform }"
:title="'Click to transform and copy: ' + transform.name"
>
{{ transform.name }}
<small class="transform-preview" v-if="transformInput">
{{ transform.preview(transformInput.slice(0, 10)) }}
</small>
<i class="fas fa-copy auto-copy-icon"></i>
</button>
<button
v-if="transformHasReverse(transform)"
@click="decodeWithTransform(transform)"
class="decode-button transform-category-ancient"
:title="'Click to decode using: ' + transform.name"
>
<i class="fas fa-undo"></i>
</button>
</div>
</div>
</div>
<!-- Technical Category -->
<div id="category-technical" class="transform-category-section">
<h4 class="category-title transform-category-technical">Technical</h4>
<div class="transform-buttons">
<div v-for="transform in getTransformsByCategory('technical')" :key="transform.name" class="transform-button-group">
<button
@click="applyTransform(transform, $event)"
class="transform-button transform-category-technical"
:class="{ active: activeTransform === transform }"
:title="'Click to transform and copy: ' + transform.name"
>
{{ transform.name }}
<small class="transform-preview" v-if="transformInput">
{{ transform.preview(transformInput.slice(0, 10)) }}
</small>
<i class="fas fa-copy auto-copy-icon"></i>
</button>
<button
v-if="transformHasReverse(transform)"
@click="decodeWithTransform(transform)"
class="decode-button transform-category-technical"
:title="'Click to decode using: ' + transform.name"
>
<i class="fas fa-undo"></i>
</button>
</div>
</div>
</div>
<!-- Randomizer Category -->
<div id="category-randomizer" class="transform-category-section randomizer-special">
<h4 class="category-title transform-category-randomizer">🎲 Randomizer - Code Switching Magic!</h4>
<p class="randomizer-description">
🌟 Apply different transforms to each word in your sentence! Creates a polyglot mix of encodings.
</p>
<div class="chaos-overlay" aria-hidden="true"></div>
<div class="transform-buttons">
<div v-for="transform in getTransformsByCategory('randomizer')" :key="transform.name" class="transform-button-group">
<button
@click="applyTransform(transform, $event)"
class="transform-button transform-category-randomizer randomizer-button"
:class="{ active: activeTransform === transform }"
:title="'Click to apply random transforms to each word!'"
>
<i class="fas fa-random"></i>
{{ transform.name }}
<small class="transform-preview">
🎯 Each word = different transform!
</small>
<i class="fas fa-copy auto-copy-icon"></i>
</button>
</div>
</div>
<div class="randomizer-info">
<h5>🎮 How it works:</h5>
<ul>
<li>🔀 Each word gets a <strong>random transform</strong></li>
<li>🎯 Mixes <strong>fantasy</strong>, <strong>ancient</strong>, and <strong>modern</strong> encodings</li>
<li>📝 Preserves punctuation and spacing</li>
<li>🔍 Check console for transform mapping details</li>
</ul>
<p><em>Example: "Hello World!" → "SGVsbG8= ᚹᚩᚱᛚᛞ!"</em></p>
</div>
</div>
</div>
</div>
<div class="output-section" v-if="transformOutput">
<div class="output-heading">
<h4>
<i class="fas fa-check-circle"></i>
Transformed Message
<small v-if="activeTransform">({{ activeTransform.name }})</small>
</h4>
</div>
<div class="output-container">
<textarea
readonly
v-model="transformOutput"
aria-label="Transformed text output"
></textarea>
<button class="copy-button" @click="copyToClipboard(transformOutput)" title="Copy to clipboard">
<i class="fas fa-copy"></i>
</button>
</div>
<div class="output-instructions">
<small><i class="fas fa-info-circle"></i> Copy this text and share it. The transformation can be reversed using the Universal Decoder below.</small>
</div>
</div>
<!-- Universal Decoder Section for Transforms Tab -->
<div class="decode-section">
<div class="section-header">
<h3>
<i class="fas fa-magic"></i> Universal Decoder
<small v-if="activeTransform">(Prioritizing {{ activeTransform.name }})</small>
</h3>
<p v-if="activeTransform && transformHasReverse(activeTransform)">
Paste encoded text to decode with {{ activeTransform.name }} or try other methods
</p>
<p v-else>Paste any encoded text to try all decoding methods at once</p>
</div>
<div class="input-container">
<textarea
id="universal-decode-input-transforms"
v-model="universalDecodeInput"
placeholder="Paste encoded text to decode automatically..."
@input="runUniversalDecode"
></textarea>
<div class="decoded-message" v-if="universalDecodeResult">
<div class="decode-method">
<span>Decoded using: <strong>{{ universalDecodeResult.method }}</strong></span>
<span v-if="activeTransform && universalDecodeResult.method === activeTransform.name" class="decode-priority">(Priority Match)</span>
</div>
<div class="decode-result">{{ universalDecodeResult.text }}</div>
<div class="decode-actions">
<button class="copy-button" @click="copyToClipboard(universalDecodeResult.text)" title="Copy decoded text">
<i class="fas fa-copy"></i> Copy
</button>
<button class="use-as-input-button" v-if="universalDecodeResult.text" @click="transformInput = universalDecodeResult.text" title="Use this as input for transforms">
<i class="fas fa-arrow-up"></i> Use as Input
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Copy History Panel -->
<div class="copy-history-panel" :class="{ 'active': showCopyHistory }">
<div class="copy-history-header">
<h3><i class="fas fa-history"></i> Copy History</h3>
<button class="close-button" @click="toggleCopyHistory" title="Close history">
<i class="fas fa-times"></i>
</button>
</div>
<div class="copy-history-content">
<div v-if="copyHistory.length === 0" class="no-history">
<p>No copy history yet. Use the app features to auto-copy content.</p>
</div>
<div v-else class="history-items">
<div v-for="(item, index) in copyHistory" :key="index" class="history-item">
<div class="history-item-header">
<span class="history-source">{{ item.source }}</span>
<span class="history-time">{{ item.timestamp }}</span>
</div>
<div class="history-content">
{{ item.content }}
</div>
<div class="history-actions">
<button class="copy-again-button" @click="copyToClipboard(item.content)" title="Copy again">
<i class="fas fa-copy"></i> Copy Again
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Global Advanced Unicode / Steg Options Panel -->
<div id="unicode-options-panel" class="unicode-options-panel">
<div class="unicode-panel-header">
<h3><i class="fas fa-sliders-h"></i> Advanced Unicode Encoding</h3>
<button class="close-button" @click="toggleUnicodePanel" title="Close options"><i class="fas fa-times"></i></button>
</div>
<div class="unicode-panel-content options-grid steg-adv-panel">
<label>
Initial Presentation
<select class="steg-initial-presentation">
<option value="emoji">Emoji (VS16)</option>
<option value="text">Text (VS15)</option>
<option value="none">None</option>
</select>
</label>
<label>
Bit-0 Selector
<select class="steg-vs-zero">
<option value="\ufe0e">VS15 (\ufe0e)</option>
<option value="\ufe0f">VS16 (\ufe0f)</option>
</select>
</label>
<label>
Bit-1 Selector
<select class="steg-vs-one">
<option value="\ufe0f">VS16 (\ufe0f)</option>
<option value="\ufe0e">VS15 (\ufe0e)</option>
</select>
</label>
<label>
Inter-bit Zero-Width
<select class="steg-inter-zw">
<option value="">None</option>
<option value="\u200C">ZWNJ (\u200C)</option>
<option value="\u200D">ZWJ (\u200D)</option>
<option value="\u200B">ZWSP (\u200B)</option>
<option value="\ufeff">BOM (\ufeff)</option>
</select>
</label>
<label>
Inter-bit Every N bits
<input class="steg-inter-every" type="number" min="1" max="8" value="1" />
</label>
<label>
Bit Order
<select class="steg-bit-order">
<option value="msb">MSB First</option>
<option value="lsb">LSB First</option>
</select>
</label>
<label>
Trailing Zero-Width
<select class="steg-trailing-zw">
<option value="\u200B">ZWSP (\u200B)</option>
<option value="\u200C">ZWNJ (\u200C)</option>
<option value="\u200D">ZWJ (\u200D)</option>
<option value="\ufeff">BOM (\ufeff)</option>
<option value="">None</option>
</select>
</label>
<button class="apply-steg-options">Apply</button>
<small class="steg-note">These options affect Unicode-based steganography encoding/decoding.</small>
</div>
</div>
<script src="js/transforms.js"></script>
<script src="js/steganography.js"></script>
<script src="js/emojiLibrary.js"></script>
<script src="js/app.js"></script>
<!-- Force emoji grid rendering -->
<script>
// Chaos particles generator for Randomizer
(function(){
const CHAOS_EMOJIS = ['✨','🌀','💥','⚡','🔥','🌈','🎲','🔮','💫','🌪️'];
function spawnChaosParticles(container, count) {
if (!container) return;
for (let i=0;i<count;i++) {
const el = document.createElement('div');
el.className = 'chaos-particle';
el.textContent = CHAOS_EMOJIS[Math.floor(Math.random()*CHAOS_EMOJIS.length)];
el.style.left = (10 + Math.random()*80) + '%';
el.style.fontSize = (14 + Math.random()*10) + 'px';
el.style.animationDelay = (Math.random()*0.2) + 's';
container.appendChild(el);
setTimeout(()=>{ if (el.parentNode) el.parentNode.removeChild(el); }, 1300);
}
}
// hook into button clicks after Vue renders
document.addEventListener('click', function(e){
const btn = e.target.closest && e.target.closest('.randomizer-button');
if (btn) {
const section = document.getElementById('category-randomizer');
const overlay = section && section.querySelector('.chaos-overlay');
if (overlay) {
section.classList.add('shake-once','randomizer-glow');
spawnChaosParticles(overlay, 10);
setTimeout(()=>section && section.classList.remove('shake-once','randomizer-glow'), 600);
}
}
}, true);
})();
// Wire up advanced steg options to steganography engine
document.addEventListener('DOMContentLoaded', function(){
document.querySelectorAll('.apply-steg-options').forEach(btn => {
btn.addEventListener('click', function(e){
e.preventDefault();
const panel = btn.closest('.steg-adv-panel');
if (!panel) return;
const initSel = panel.querySelector('.steg-initial-presentation')?.value || 'emoji';
const vs0 = panel.querySelector('.steg-vs-zero')?.value || '\\ufe0e';
const vs1 = panel.querySelector('.steg-vs-one')?.value || '\\ufe0f';
const inter = panel.querySelector('.steg-inter-zw')?.value || null;
const trailing = panel.querySelector('.steg-trailing-zw')?.value || null;
const every = parseInt(panel.querySelector('.steg-inter-every')?.value || '1', 10);
const order = panel.querySelector('.steg-bit-order')?.value || 'msb';
if (window.steganography && window.steganography.setStegOptions) {
window.steganography.setStegOptions({
initialPresentation: initSel,
bitZeroVS: vs0,
bitOneVS: vs1,
interBitZW: inter,
interBitEvery: isNaN(every) ? 1 : Math.max(1, Math.min(8, every)),
trailingZW: trailing,
bitOrder: order
});
}
});
});
});
// Function to initialize emoji grid with retries
function initEmojiGrid(retryCount) {
retryCount = retryCount || 0;
const maxRetries = 5;
console.log('Initializing emoji grid, attempt:', retryCount + 1);
// Get the emoji library element
const emojiLibrary = document.querySelector('.emoji-library');
// Access the emoji grid container without forcing styles
const emojiGridContainer = document.getElementById('emoji-grid-container');
if (emojiGridContainer) {
console.log('Found emoji grid container, initializing...');
// Only set content, let CSS handle display
emojiGridContainer.innerHTML = '<div class="loading-emojis">Loading emoji grid...</div>';
// Manually render emoji grid
if (window.emojiLibrary && window.emojiLibrary.renderEmojiGrid) {
try {
window.emojiLibrary.renderEmojiGrid('emoji-grid-container', function(emoji) {
// Simulate emoji selection by calling the Vue method if possible
const app = document.getElementById('app').__vue__;
if (app && app.selectEmoji) {
app.selectEmoji(emoji);
}
});
console.log('Emoji grid successfully rendered');
} catch (error) {
console.error('Error rendering emoji grid:', error);
}
} else {
console.warn('Emoji library not yet available, will retry');
if (retryCount < maxRetries) {
setTimeout(() => initEmojiGrid(retryCount + 1), 500);
}
}
} else {
console.warn('Emoji grid container not found, will retry');
if (retryCount < maxRetries) {
setTimeout(() => initEmojiGrid(retryCount + 1), 500);
}
}
}
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
// First attempt after a short delay to ensure Vue has initialized
setTimeout(initEmojiGrid, 500);
// Also initialize when switching to the steganography tab
const app = document.getElementById('app');
if (app && app.__vue__) {
const vue = app.__vue__;
// Watch for tab changes
const originalWatch = vue.$watch;
if (originalWatch) {
vue.$watch('activeTab', function(newTab) {
if (newTab === 'steganography') {
console.log('Switched to steganography tab, initializing emoji grid');
setTimeout(initEmojiGrid, 100);
}
});
}
}
});
</script>
</body>
</html>