Lab Tool Expansion Plan: Candidate Text Processing Tools
Introduction
I asked Gemini to review lilting.ch/lab and provide a comparison with DevToys.
If DevToys is “a toolbox for programmers,” your site feels like “a workshop for creators (especially for imagery, AI, and web production)”, so the direction is quite different — and interesting.
That’s exactly right. The Lab currently has many image-processing tools, but it’s light on text data processing.
Current tool distribution (31 total):
| Category | Count |
|---|---|
| Image Conversion | 4 |
| Image Transform | 4 |
| Image Editing | 4 |
| Image Effects | 3 |
| Viewers | 6 |
| NLP | 4 |
| Utility | 6 |
For text processing, we do have NLP-leaning items like “Markdown editor,” “morphological analysis,” and “OCR,” but we lack developer-oriented tools such as a JSON formatter and Base64 conversion.
Candidate Tools
I listed candidate additions with priorities.
| Priority | Tool | Use case |
|---|---|---|
| High | JSON Formatter | Pretty-print, validate, minify JSON |
| High | Base64 Converter | Encode/decode text or images |
| Medium | YAML Formatter | Format/validate YAML; convert with JSON |
| Medium | Text Diff | Show diff between two texts |
| Medium | URL Encode/Decode | Convert Japanese URLs, etc. |
| Medium | Timestamp Converter | UNIX time ↔ date-time |
| Medium | HTML Entity Converter | < ↔ < and so on |
| Low | UUID Generator | Random ID generation |
| Low | Hash Generator | MD5/SHA256 calculation |
| Low | JWT Decoder | Inspect authentication tokens |
| Low | .env Editor | Format/validate env files |
| Low | INI Editor | Format/validate INI files |
Implementation Specs for Each Tool
JSON Formatter (Priority: High)
Overview:
- Pretty-print JSON strings
- Minify (compress)
- Validation (detect syntax errors)
- Syntax highlighting
UI:
- Left: input text area
- Right: output text area (with highlighting)
- Top: indent settings (2/4 spaces, tab), pretty/minify buttons
- On error: show error position and message
Library candidates:
- Syntax highlighting: Prism.js or custom CSS
- JSON handling: browser-native
JSON.parse()/JSON.stringify()is sufficient
Implementation notes:
JSON.stringify(obj, null, indent)for pretty printJSON.stringify(obj)for minify- Use try-catch for validation; extract line numbers from error messages
Base64 Converter (Priority: High)
Overview:
- Text → Base64 encode
- Base64 → Text decode
- Image → Base64 (data URI)
- Base64 → Image preview
UI:
- Tabs: “Text” and “Image”
- Text mode: input/output text areas + encode/decode buttons
- Image mode: drag-and-drop area + Base64 output + preview
Library candidates:
- Browser APIs:
btoa()/atob()(ASCII),TextEncoder/TextDecoder(UTF-8) - Image handling: FileReader API
Implementation notes:
- UTF-8-safe encoding:
const base64 = btoa(unescape(encodeURIComponent(text))); - UTF-8-safe decoding:
const text = decodeURIComponent(escape(atob(base64))); - Data URI for images:
data:image/png;base64,${base64}
YAML Formatter (Priority: Medium)
Overview:
- Format YAML strings
- Validation (detect syntax errors)
- JSON ↔ YAML conversion
UI:
- Left: input text area
- Right: output text area
- Top: format button, to-JSON button, to-YAML button
- On error: show error position and message
Library candidates:
Implementation notes:
- With js-yaml:
import yaml from 'js-yaml'; // YAML → JSON const obj = yaml.load(yamlString); const json = JSON.stringify(obj, null, 2); // JSON → YAML const yamlOutput = yaml.dump(JSON.parse(jsonString)); - Because YAML indentation is meaningful, expose options for indent width
Text Diff (Priority: Medium)
Overview:
- Place two texts side-by-side
- Highlight differences (additions = green, deletions = red)
- Toggle line-level/char-level
- Toggle unified/split view
UI:
- Top: two input text areas (horizontal or vertical)
- Bottom: diff display area
- Options: ignore whitespace, case-insensitive
Library candidates:
- diff: a lightweight diff library
- monaco-editor: VS Code’s editor (has diff view but heavy)
Implementation notes:
- Use
diffLines()/diffChars()from the diff library - Convert results to HTML and highlight
- Avoid monaco-editor for simple use cases due to bundle size
URL Encode/Decode (Priority: Medium)
Overview:
- Text → URL-encode
- URL-encoded text → decode
- Toggle full-URL vs component encoding
UI:
- Input text area
- Output text area
- Buttons: encode/decode
- Option: switch between
encodeURIandencodeURIComponent
Library candidates:
- Browser APIs:
encodeURI()/decodeURI(),encodeURIComponent()/decodeURIComponent()
Implementation notes:
encodeURI: encodes a whole URL (keeps/,?,&, etc.)encodeURIComponent: encodes parts like query params (converts all special chars)- It helps to explain the difference in the UI
Timestamp Converter (Priority: Medium)
Overview:
- UNIX timestamp → human-readable date-time
- Date-time → UNIX timestamp
- Toggle milliseconds/seconds
- Time zones (UTC/local/custom)
UI:
- Top: UNIX timestamp input + “Now” button
- Bottom: date-time display (multiple formats)
- Reverse: date-time input → timestamp output
- Time zone dropdown
Library candidates:
- Browser-native:
Dateobject is enough - Formatting: date-fns (lightweight), dayjs (Moment.js alternative)
Implementation notes:
- Basic conversions:
// タイムスタンプ → 日時 const date = new Date(timestamp * 1000); // 秒の場合 const date = new Date(timestamp); // ミリ秒の場合 // 日時 → タイムスタンプ const timestamp = Math.floor(date.getTime() / 1000); // 秒 const timestampMs = date.getTime(); // ミリ秒 - ISO 8601:
date.toISOString() - Localized:
date.toLocaleString('ja-JP') - Auto-detect seconds vs milliseconds by digit length (10 = sec, 13 = ms)
HTML Entity Converter (Priority: Medium)
Overview:
- HTML special characters → entities (escape)
- Entities → HTML special characters (unescape)
- Support numeric refs (
<) and named refs (<)
UI:
- Input text area
- Output text area
- Buttons: encode/decode
- Option: convert all characters vs minimal set
Library candidates:
- he: go-to for HTML entities
- Hand-rolled: fine if you only need the basics (
<>&"')
Implementation notes:
- Basic escape:
function escapeHtml(text) { const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.replace(/[&<>"']/g, c => map[c]); } - Unescape (via browser API):
function unescapeHtml(text) { const doc = new DOMParser().parseFromString(text, 'text/html'); return doc.documentElement.textContent; } - To convert every char to a numeric ref:
&#${char.charCodeAt(0)};
UUID Generator (Priority: Low)
Overview:
- Generate UUID v4 (random)
- Bulk-generate multiple values
- Toggle upper/lower case
- Toggle with/without hyphens
UI:
- Generate button
- Count input (1–100)
- Output text area (with copy button)
- Options: upper/lower, hyphen on/off
Library candidates:
- uuid: the standard choice
- Browser-native:
crypto.randomUUID()(modern browsers)
Implementation notes:
- If
crypto.randomUUID()is available, no library needed - Remove hyphens:
uuid.replace(/-/g, '') - Uppercase:
uuid.toUpperCase()
Hash Generator (Priority: Low)
Overview:
- Compute a hash from text
- Algorithms: MD5, SHA-1, SHA-256, SHA-512
- Compute from files as well
UI:
- Input text area or file drop area
- Algorithm selection (radio or dropdown)
- Output: hash value (with copy button)
Library candidates:
- Web Crypto API:
crypto.subtle.digest()(SHA family) - js-md5: for MD5 (not in Web Crypto)
- crypto-js: supports multiple algorithms
Implementation notes:
- Web Crypto example:
const buffer = new TextEncoder().encode(text); const hashBuffer = await crypto.subtle.digest('SHA-256', buffer); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); - MD5 is discouraged but often requested, so include it
JWT Decoder (Priority: Low)
Overview:
- Decode a JWT token and show contents
- Display header, payload, and signature separately
- Convert the
exptimestamp to a human-readable date - Do not verify signatures (no secret key)
UI:
- Input: JWT token (text area)
- Output: header (JSON), payload (JSON), signature (Base64)
- If
expexists, show “expired” or “in N days”
Library candidates:
- No library needed: Base64 decode is enough
Implementation notes:
- JWT has the form
header.payload.signature(dot-separated) - Header and payload use Base64URL encoding
- Base64URL decode:
function base64UrlDecode(str) { const base64 = str.replace(/-/g, '+').replace(/_/g, '/'); return decodeURIComponent(escape(atob(base64))); } expis a UNIX timestamp in seconds
.env Editor (Priority: Low)
Overview:
- Format
.envfiles (KEY=value) - Detect duplicate keys
- Preserve comment lines
- Normalize quoting of values
UI:
- Input text area (.env format)
- Output: table view (key/value list)
- Options: sort (alphabetical), unify quoting
Library candidates:
- dotenv: standard but Node.js-oriented
- Homegrown parser: fine for browsers
Implementation notes:
- Basic parsing:
function parseEnv(text) { const result = {}; for (const line of text.split('\n')) { if (line.startsWith('#') || !line.includes('=')) continue; const [key, ...valueParts] = line.split('='); result[key.trim()] = valueParts.join('=').trim(); } return result; } - Remove quotes:
value.replace(/^["']|["']$/g, '') - Skip multiline (heredoc-like) values to keep it simple
INI Editor (Priority: Low)
Overview:
- Format INI files
- Parse sections (
[section]) and key=value pairs - Validation (detect syntax errors)
- Preserve comment lines
UI:
- Input text area (INI format)
- Output: tree view (section > key/value)
- Options: sort, convert to JSON
Library candidates:
- ini: Node.js-oriented but can be used in browsers
- Homegrown parser: simple enough for sections and key=value
Implementation notes:
- Basic parsing:
function parseIni(text) { const result = {}; let currentSection = ''; for (const line of text.split('\n')) { const trimmed = line.trim(); if (trimmed.startsWith(';') || trimmed.startsWith('#')) continue; if (trimmed.startsWith('[') && trimmed.endsWith(']')) { currentSection = trimmed.slice(1, -1); result[currentSection] = {}; } else if (trimmed.includes('=')) { const [key, ...valueParts] = trimmed.split('='); const target = currentSection ? result[currentSection] : result; target[key.trim()] = valueParts.join('=').trim(); } } return result; } - Allow keys without a section (root level)
Implementation Approach
Adding Categories
Current category definition (src/lib/lab-tools.ts):
export type LabToolCategory =
| 'image-convert'
| 'image-transform'
| 'image-edit'
| 'image-effect'
| 'viewer'
| 'nlp'
| 'utility';
Options to add a dedicated category for text processing:
text-process: text processing (JSON, Base64, URL, hashing, etc.)developer: developer tools (broader scope)
Alternatively, include them under the existing utility for now and split later as the number grows.
Tool Registration Steps
- Create a new Astro file under
src/pages/lab/ - Add an entry to the
toolsarray insrc/lib/lab-tools.ts - The list view at
src/pages/lab/index.astrowill pick it up automatically
Shared Components
Since text-processing tools have similar UIs, shared components will help:
TextArea: text area with a copy buttonConvertButton: convert buttonOptionToggle: option toggle
That said, I’ll only get around to implementation when I have a bit of time… so probably when the mood strikes.