Last active
April 7, 2025 01:09
-
-
Save rikonor/7de9b95e1e89e068600ec91c10916b2d to your computer and use it in GitHub Desktop.
dots
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState, useEffect } from 'react'; | |
const DotGridEncoder = () => { | |
// State variables for customization | |
const [text, setText] = useState('life is war'); | |
const [dotSize, setDotSize] = useState(4); | |
const [gridSpacing, setGridSpacing] = useState(8); | |
const [encoding, setEncoding] = useState('binary'); // 'binary', 'ascii', 'morse' | |
const [colorScheme, setColorScheme] = useState('monochrome'); // 'monochrome', 'gradient', 'rainbow' | |
// Calculate grid dimensions for a more square layout | |
const totalBits = text.length * 8; // Approximate bits needed for encoding | |
const gridWidth = Math.ceil(Math.sqrt(totalBits)); // Square root for square layout | |
const gridHeight = Math.ceil(totalBits / gridWidth); | |
// Function to encode text into dot grid | |
const encodeText = () => { | |
let encodedBits = []; | |
// Handle empty input | |
if (!text || text.length === 0) { | |
return Array(8).fill().map(() => Array(8).fill(false)); | |
} | |
// Reset grid dimensions based on encoding method and text length | |
let estimatedBits; | |
if (encoding === 'morse') { | |
// Morse encoding tends to generate more bits | |
estimatedBits = text.length * 15; | |
} else { | |
estimatedBits = text.length * 8; | |
} | |
// Adjust gridWidth and gridHeight for square layout | |
const squareSide = Math.ceil(Math.sqrt(estimatedBits)); | |
switch(encoding) { | |
case 'binary': | |
// Convert text to binary representation | |
for (let i = 0; i < text.length; i++) { | |
const charCode = text.charCodeAt(i); | |
const binaryStr = charCode.toString(2).padStart(8, '0'); | |
for (let j = 0; j < binaryStr.length; j++) { | |
encodedBits.push(binaryStr[j] === '1'); | |
} | |
} | |
break; | |
case 'ascii': | |
// Use ASCII values directly | |
for (let i = 0; i < text.length; i++) { | |
const value = text.charCodeAt(i); | |
for (let j = 0; j < 8; j++) { | |
encodedBits.push(Boolean((value >> j) & 1)); | |
} | |
} | |
break; | |
case 'morse': | |
// Simple Morse code mapping | |
const morseMap = { | |
'a': '.-', 'b': '-...', 'c': '-.-.', 'd': '-..', 'e': '.', 'f': '..-.', | |
'g': '--.', 'h': '....', 'i': '..', 'j': '.---', 'k': '-.-', 'l': '.-..', | |
'm': '--', 'n': '-.', 'o': '---', 'p': '.--.', 'q': '--.-', 'r': '.-.', | |
's': '...', 't': '-', 'u': '..-', 'v': '...-', 'w': '.--', 'x': '-..-', | |
'y': '-.--', 'z': '--..', ' ': '/' | |
}; | |
for (let i = 0; i < text.length; i++) { | |
const char = text[i].toLowerCase(); | |
if (morseMap[char]) { | |
for (let j = 0; j < morseMap[char].length; j++) { | |
encodedBits.push(morseMap[char][j] === '.' || morseMap[char][j] === '-'); | |
// Add a spacer bit between morse symbols | |
if (j < morseMap[char].length - 1) { | |
encodedBits.push(false); | |
} | |
} | |
// Add three spacer bits between characters | |
if (i < text.length - 1) { | |
encodedBits.push(false); | |
encodedBits.push(false); | |
} | |
} | |
} | |
break; | |
} | |
// Fill the grid row by row, left to right | |
const grid = Array(gridHeight).fill().map(() => Array(gridWidth).fill(false)); | |
let bitIndex = 0; | |
for (let row = 0; row < gridHeight && bitIndex < encodedBits.length; row++) { | |
for (let col = 0; col < gridWidth && bitIndex < encodedBits.length; col++) { | |
grid[row][col] = encodedBits[bitIndex]; | |
bitIndex++; | |
} | |
} | |
return grid; | |
}; | |
// Get dot color based on position and color scheme | |
const getDotColor = (row, col, active) => { | |
if (!active) return '#eaeaea'; | |
switch(colorScheme) { | |
case 'monochrome': | |
return '#333333'; | |
case 'gradient': | |
// Creates a gradient from blue to red | |
const progress = (row * gridWidth + col) / (gridWidth * gridHeight); | |
return `rgb(${Math.round(progress * 255)}, 0, ${Math.round(255 - progress * 255)})`; | |
case 'rainbow': | |
// Creates a rainbow effect | |
const hue = ((row * gridWidth + col) / (gridWidth * gridHeight)) * 360; | |
return `hsl(${hue}, 70%, 50%)`; | |
default: | |
return '#333333'; | |
} | |
}; | |
// Calculate proper dimensions for a square-like grid | |
let estimatedBits; | |
// Handle empty input case | |
if (!text || text.length === 0) { | |
estimatedBits = 64; // Default to an 8x8 grid for empty input | |
} else if (encoding === 'morse') { | |
estimatedBits = text.length * 15; // Morse code is variable length but generally longer | |
} else { | |
estimatedBits = text.length * 8; // Binary and ASCII use 8 bits per character | |
} | |
// Calculate grid dimensions for a more square layout | |
const squareSide = Math.ceil(Math.sqrt(estimatedBits)); | |
const adjustedWidth = squareSide; | |
const adjustedHeight = Math.ceil(estimatedBits / adjustedWidth); | |
// Create the encoded grid | |
const encodedGrid = encodeText(); | |
// Ensure we have valid dimensions even with empty input | |
const displayWidth = encodedGrid[0]?.length || 8; | |
const displayHeight = encodedGrid.length || 8; | |
return ( | |
<div className="flex flex-col items-center max-w-4xl mx-auto p-4 bg-gray-50 rounded-lg shadow"> | |
<h2 className="text-2xl font-bold mb-4">"{text}" Encoded as Dots</h2> | |
<div className="mb-6 w-full"> | |
<div className="flex flex-wrap gap-4 mb-4"> | |
<div className="flex-1"> | |
<label className="block text-sm font-medium mb-1">Text to Encode</label> | |
<input | |
type="text" | |
value={text} | |
onChange={(e) => setText(e.target.value)} | |
className="w-full p-2 border rounded" | |
/> | |
</div> | |
<div className="w-32"> | |
<label className="block text-sm font-medium mb-1">Dot Size</label> | |
<input | |
type="range" | |
min="2" | |
max="6" | |
value={dotSize} | |
onChange={(e) => setDotSize(parseInt(e.target.value))} | |
className="w-full" | |
/> | |
</div> | |
<div className="w-32"> | |
<label className="block text-sm font-medium mb-1">Grid Spacing</label> | |
<input | |
type="range" | |
min="6" | |
max="12" | |
value={gridSpacing} | |
onChange={(e) => setGridSpacing(parseInt(e.target.value))} | |
className="w-full" | |
/> | |
</div> | |
</div> | |
<div className="flex flex-wrap gap-4"> | |
<div className="flex-1"> | |
<label className="block text-sm font-medium mb-1">Encoding Method</label> | |
<select | |
value={encoding} | |
onChange={(e) => setEncoding(e.target.value)} | |
className="w-full p-2 border rounded" | |
> | |
<option value="binary">Binary</option> | |
<option value="ascii">ASCII</option> | |
<option value="morse">Morse Code</option> | |
</select> | |
</div> | |
<div className="flex-1"> | |
<label className="block text-sm font-medium mb-1">Color Scheme</label> | |
<select | |
value={colorScheme} | |
onChange={(e) => setColorScheme(e.target.value)} | |
className="w-full p-2 border rounded" | |
> | |
<option value="monochrome">Monochrome</option> | |
<option value="gradient">Blue-Red Gradient</option> | |
<option value="rainbow">Rainbow</option> | |
</select> | |
</div> | |
</div> | |
</div> | |
<div className="relative bg-white p-4 border rounded"> | |
<svg | |
width={displayWidth * gridSpacing} | |
height={displayHeight * gridSpacing} | |
className="overflow-visible" | |
> | |
{encodedGrid.map((row, rowIndex) => | |
row.map((isActive, colIndex) => ( | |
<circle | |
key={`${rowIndex}-${colIndex}`} | |
cx={colIndex * gridSpacing + gridSpacing/2} | |
cy={rowIndex * gridSpacing + gridSpacing/2} | |
r={isActive ? dotSize : dotSize/2} | |
fill={getDotColor(rowIndex, colIndex, isActive)} | |
className="transition-all duration-300" | |
/> | |
)) | |
)} | |
</svg> | |
</div> | |
<div className="mt-4 text-sm text-gray-700"> | |
<p> | |
{text ? `Encoding "${text}" using ${encoding} encoding.` : 'Enter text to see it encoded as dots.'} | |
</p> | |
<p className="italic mt-1"> | |
{encoding === 'binary' && 'Each character is represented by its 8-bit binary ASCII value.'} | |
{encoding === 'ascii' && 'Each bit in the ASCII value is represented by a dot.'} | |
{encoding === 'morse' && 'Dots and dashes of Morse code are represented by dots.'} | |
</p> | |
</div> | |
</div> | |
); | |
}; | |
export default DotGridEncoder; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment