6.6 KiB
English Style Converter — Design Spec
Date: 2025-04-12 Status: Approved
Overview
A web app that takes a normal English sentence and converts it into various English styles and tones using an LLM. Single-page, minimal, light-themed, with an intensity slider for fine control and prompt transparency.
Architecture
Approach: Simple and Direct — single SvelteKit project with API routes handling LLM calls. No separate backend, no database, no auth.
Tech Stack
- Framework: SvelteKit (latest)
- UI: Svelte 5 with runes (, )
- Language: TypeScript
- Testing: Vitest (unit + integration)
- LLM: OpenAI-compatible API (Ollama default, any compatible provider)
- Styling: Delegated to UI specialist tools (uncodixfy, stitch MCP). Direction: minimal, clean, light colors only, no dark mode.
Project Structure
english-styler/ src/ lib/ styles.ts - Style definitions (categories, subtypes, prompt text) llm.ts - OpenAI-compatible client abstraction types.ts - Shared TypeScript types routes/ +page.svelte - Main converter UI +page.ts - Page load (optional) api/ convert/ +server.ts - POST endpoint app.html - SvelteKit HTML shell static/ .env - LLM config svelte.config.js vite.config.ts tsconfig.json package.json
Style System
Types
Style: id: string (e.g. "sarcastic", "british-polite", "got-kingslanding") label: string (e.g. "Sarcastic", "Polite (British)") categoryId: string (e.g. "general", "british", "american", "got") promptModifier: string (e.g. "Rewrite in a sarcastic, snarky tone with biting wit")
StyleCategory: id: string label: string emoji: string
ConversionRequest: text: string styleId: string intensity: number (1-5)
ConversionResponse: original: string converted: string styleId: string intensity: number systemPrompt: string (Full system prompt for transparency display) userMessage: string (Full user message for transparency display)
Style Categories and Sub-styles
| Category | Emoji | Sub-styles |
|---|---|---|
| General | drama | Sarcastic, Formal, Casual, Academic, Poetic, Passive-Aggressive |
| British Slang | gb | Polite, Formal, Witty, Gentlemanly, Upper Class, Royal, Victorian, Downton Abbey |
| American Slang | us | New Yorker, Black American Slang, Southern, Redneck |
| Fun | pirate | Pirate, Shakespearean, Gen Z Slang |
| Game of Thrones | dragon | Kings Landing, Wildlings, Winterfell |
| Dystopian | newspaper | Newspeak (Orwellian) |
Intensity Levels
| Level | Label | Prompt effect |
|---|---|---|
| 1 | Subtle | lightly hint at a [style] tone |
| 2 | Moderate | rewrite with a [style] tone |
| 3 | Strong | rewrite strongly in a [style] style |
| 4 | Heavy | rewrite completely in [style] - fully commit to the voice |
| 5 | Maximum | go absolutely all-out [style] - no restraint |
Intensity mapping stored in lib/styles.ts, not hardcoded in LLM call.
LLM Abstraction
Configuration (.env only)
OPENAI_BASE_URL=http://localhost:11434/v1 OPENAI_API_KEY=ollama OPENAI_MODEL=llama3
No UI-based provider config. Server-side only.
Client (lib/llm.ts)
Single OpenAI-compatible client using fetch against /v1/chat/completions. Works with Ollama (default) and any OpenAI-compatible API.
Returns converted text plus full prompt for transparency display.
System Prompt Template
You are an expert English style converter. Rewrite the users text {intensityInstruction}. {stylePromptModifier} Preserve the core meaning but fully transform the voice and tone. Output ONLY the converted text - no explanations, no labels, no quotes.
API Endpoint
POST /api/convert
- Request body: { text, styleId, intensity }
- Response: { original, converted, styleId, intensity, systemPrompt, userMessage }
- Validation:
- text non-empty (after trimming)
- styleId exists in styles
- intensity is integer 1-5
- Errors:
- 400 for bad input (with human-readable message)
- 502 for LLM call failure (with friendly message)
- No retry logic for MVP1
Frontend UI
Layout
Single page, centered, minimal. Light palette only.
- Title: "English Style Converter" with subtitle
- Input textarea for text entry
- Two-step style selector: Category dropdown then Sub-style dropdown
- Intensity slider (1-5, default 3) with labels "Subtle" to "Maximum"
- Convert button with loading state
- Output display area with Copy button
- Collapsible "Show prompt" section below output revealing system and user prompts
Interaction Flow
- User types or pastes text
- Selects category, sub-style dropdown populates
- Adjusts intensity slider (default: 3)
- Clicks Convert, loading state
- Result appears with Copy button
- "Show prompt" reveals full system + user prompt (collapsible, hidden by default)
- Errors display in the output area, never as browser alerts
Svelte 5 Runes
- () for input text, selected style, intensity, output, loading, error, prompt visibility
- () for is category selected, is convert disabled, etc.
UI Details
- Light palette - white/off-white background, subtle borders, accent color on Convert button
- No dark mode
- Responsive - stacked full-width on mobile, centered max-width on desktop
- Copy button - navigator.clipboard with confirmation
- No streaming - full response then display (v2 candidate)
Testing Strategy
Automated Tests (Vitest)
| Layer | Tests |
|---|---|
| lib/styles.ts | Style lookup, category filtering, all styles have valid promptModifiers |
| lib/llm.ts | Prompt construction correctness (mock HTTP, verify prompt) |
| /api/convert | Input validation (empty text, bad style, out-of-range intensity), error responses |
Not Testing (MVP1)
- E2E, visual regression, snapshots, LLM response content
Manual Testing Checklist (Pre-launch)
- Submit empty text returns 400
- Submit with invalid style returns 400
- Submit with intensity 0 or 6 returns validation error
- LLM unreachable returns 502 with friendly message
- Each category styles load in dropdowns
- Intensity slider updates label
- Copy button works
- Prompt section expands/collapses with correct content
- Works on mobile viewport
Scope - MVP1
In scope:
- Single style at a time
- Intensity slider (1-5)
- Collapsible prompt display
- .env-only LLM config
- OpenAI-compatible client (Ollama default)
- Light-only, minimal UI
- Unit + integration tests for backend logic
Explicitly out of scope (v2 candidates):
- Multi-style / compare mode
- Conversion history
- UI-based provider settings
- Streaming responses
- Dark mode
- E2E tests
- Database or auth