From 4ca3a9f1a9df0aa106768ead72be60280e47ca32 Mon Sep 17 00:00:00 2001 From: Santhosh Janardhanan Date: Sun, 12 Apr 2026 20:21:21 -0400 Subject: [PATCH] Add English Style Converter design spec --- ...25-04-12-english-style-converter-design.md | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 docs/superpowers/specs/2025-04-12-english-style-converter-design.md diff --git a/docs/superpowers/specs/2025-04-12-english-style-converter-design.md b/docs/superpowers/specs/2025-04-12-english-style-converter-design.md new file mode 100644 index 0000000..4316fc8 --- /dev/null +++ b/docs/superpowers/specs/2025-04-12-english-style-converter-design.md @@ -0,0 +1,216 @@ +# 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 + +1. User types or pastes text +2. Selects category, sub-style dropdown populates +3. Adjusts intensity slider (default: 3) +4. Clicks Convert, loading state +5. Result appears with Copy button +6. "Show prompt" reveals full system + user prompt (collapsible, hidden by default) +7. 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) + +1. Submit empty text returns 400 +2. Submit with invalid style returns 400 +3. Submit with intensity 0 or 6 returns validation error +4. LLM unreachable returns 502 with friendly message +5. Each category styles load in dropdowns +6. Intensity slider updates label +7. Copy button works +8. Prompt section expands/collapses with correct content +9. 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