# 2.1 — Editor **Next Step:** → [Results Panel](../2.2-results-panel/2.2-results-panel.md) --- ## Page Metadata | Property | Value | |----------|-------| | **Scenario** | 02 — Calculation Experience | | **Page Number** | 2.1 | | **Platform** | Web (PWA), portable to macOS/Windows | | **Page Type** | Embedded Panel (within App Shell main area) | | **Viewport** | All breakpoints | | **Interaction** | Keyboard-primary, mouse secondary | --- ## Overview **Page Purpose:** The editor is where calculations happen. Users type natural-language math expressions, define variables, add comments, and organize their thinking. It must feel like a fast, responsive text editor — not a calculator widget. **User Situation:** User is actively thinking through numbers. They're writing a budget, converting units, figuring out a mortgage, or doing quick math. The editor must never get in their way — every keystroke should feel instant. **Success Criteria:** - Typing latency < 16ms (60fps) - Results update within 50ms of pause (debounce) - Syntax highlighting aids comprehension without distraction - Errors are visible but non-intrusive - Visual hierarchy makes 50-line documents scannable **Entry Points:** - Opening a document (tab click, sidebar double-click, new document) - Returning to active document **Exit Points:** - Switching tabs (editor content swaps) - Closing document --- ## Reference Materials **Existing Implementation:** - `calcpad-web/src/editor/CalcEditor.tsx` — Current CodeMirror wrapper - `calcpad-web/src/editor/calcpad-language.ts` — Syntax highlighting - `calcpad-web/src/editor/error-display.ts` — Error underlines + gutter - `calcpad-web/src/editor/inline-results.ts` — Zebra striping **Design System:** - [Spacing Scale](../../../D-Design-System/00-design-system.md#spacing-scale) - [Type Scale](../../../D-Design-System/00-design-system.md#type-scale) --- ## Layout Structure ``` ┌──────────────────────────────────────────┐ │ [Gutter] [Line Content] │ │ │ │ 1 │ # Monthly Budget │ ← heading (bold, larger) │ 2 │ │ ← empty line │ 3 │ // Income │ ← comment (muted) │ 4 │ salary = 5000 │ ← variable assignment │ 5 │ freelance = 1200 │ ← variable assignment │ 6 │ total_income = salary + freelance │ ← expression │ 7 │ │ │ 8 │ // Expenses │ ← comment │ 9 │ rent = 1500 │ │ 10 │ groceries = 400 │ │ 11 │ utilities = rent * 5% ̰ ̰ ̰ ̰ │ ← error underline │ 12 │ │ │ 13 │ total_expenses = sum │ ← aggregator │ 14 │ savings = total_income - total_exp │ │ │ │ │ │ │ └──────────────────────────────────────────┘ Zebra striping on alternating lines ``` --- ## Spacing | Property | Token | Pixels | |----------|-------|--------| | Content padding top/bottom | space-sm | 8px | | Line padding horizontal | space-md | 12px | | Gutter width | — | 40px (auto-expands for > 999 lines) | | Gutter padding right | space-xs | 6px | | Line height | — | 24px (15px font × 1.6) | | Error gutter width | — | 20px | **Change from current:** Reduced line padding from 16px → 12px to match macOS's tighter feel. --- ## Typography | Element | Size | Weight | Typeface | Color | |---------|------|--------|----------|-------| | Line content | text-md (15px) | 400 | system mono | var(--text) | | Headings (# lines) | text-md (15px) | 700 | system mono | var(--text-h) | | Comments (// lines) | text-md (15px) | 400 italic | system mono | var(--text) at 50% opacity | | Variable names | text-md (15px) | 400 | system mono | var(--syntax-variable) | | Numbers | text-md (15px) | 400 | system mono | var(--syntax-number) | | Operators | text-md (15px) | 400 | system mono | var(--syntax-operator) | | Keywords | text-md (15px) | 500 | system mono | var(--syntax-keyword) | | Functions | text-md (15px) | 400 | system mono | var(--syntax-function) | | Currency symbols | text-md (15px) | 400 | system mono | var(--syntax-currency) | | Line numbers (gutter) | text-xs (13px) | 400 | system mono | var(--text) at 40% opacity | | Active line number | text-xs (13px) | 600 | system mono | var(--text) | --- ## Syntax Highlighting Tokens New CSS custom properties for syntax colors, per-theme: | Token | Light | Dark | Matrix | |-------|-------|------|--------| | --syntax-variable | #4f46e5 (indigo-600) | #a5b4fc (indigo-300) | #00ff41 | | --syntax-number | #0d9488 (teal-600) | #5eead4 (teal-300) | #00cc33 | | --syntax-operator | #6b6375 (text) | #9ca3af (text) | #00ff41 | | --syntax-keyword | #7c3aed (violet-600) | #c4b5fd (violet-300) | #39ff14 | | --syntax-function | #2563eb (blue-600) | #93c5fd (blue-300) | #00ff41 | | --syntax-currency | #d97706 (amber-600) | #fcd34d (amber-300) | #ffff00 | | --syntax-comment | rgba(text, 0.5) | rgba(text, 0.5) | rgba(#00ff41, 0.4) | | --syntax-heading | var(--text-h) | var(--text-h) | #00ff41 | | --syntax-error | #e53e3e | #fc8181 | #ff0000 | --- ## Visual Hierarchy Improvements ### Headings (`# lines`) | Property | Value | |----------|-------| | Font weight | 700 (bold) | | Color | var(--text-h) — strongest text color | | Top margin | 8px extra (visual section break) — only if preceded by non-empty line | | Bottom margin | 0 (heading belongs to content below) | | Background | None (clean) | ### Comments (`// lines`) | Property | Value | |----------|-------| | Font style | Italic | | Opacity | 50% of text color | | No background stripe | Comments skip zebra striping (visually distinct already) | ### Empty Lines | Property | Value | |----------|-------| | Height | 24px (same as content lines) | | Background | Normal zebra stripe pattern | | Purpose | Visual breathing room, section separators | ### Active Line | Property | Value | |----------|-------| | Background | var(--accent-bg) — subtle accent tint | | Gutter | Line number bold + full opacity | | Transition | background 0.1s | --- ## Error Display ### Error Underline **OBJECT ID:** `editor-error-underline` | Property | Value | |----------|-------| | Style | wavy underline | | Color | var(--syntax-error) | | Thickness | 1.5px | | Scope | Underlines the specific token/expression that errored | ### Error Gutter Marker **OBJECT ID:** `editor-error-gutter` | Property | Value | |----------|-------| | Icon | ⚠ (warning triangle) | | Size | 14px | | Color | var(--syntax-error) | | Position | Error gutter column (20px wide, left of line numbers) | | Hover | Tooltip with error message text | ### Error Tooltip **OBJECT ID:** `editor-error-tooltip` | Property | Value | |----------|-------| | Trigger | Hover over error gutter marker OR underlined text | | Background | var(--bg-secondary) | | Border | 1px solid var(--border) | | Border-radius | 4px | | Padding | 4px 8px | | Font | text-xs, system sans, var(--syntax-error) | | Shadow | 0 2px 8px rgba(0,0,0,0.15) | | Max width | 300px | | Position | Below the error line, left-aligned with gutter | --- ## Zebra Striping | Property | Value | |----------|-------| | Pattern | Even-numbered lines (matching current implementation) | | Light mode | rgba(0, 0, 0, 0.02) — reduced from 0.025 | | Dark mode | rgba(255, 255, 255, 0.025) — reduced from 0.035 | | Matrix mode | rgba(0, 255, 65, 0.03) — green tint | | Skip on | Comment lines (already visually distinct) | --- ## Autocomplete **OBJECT ID:** `editor-autocomplete` | Property | Value | |----------|-------| | Trigger | Typing 2+ characters that match a variable, function, or keyword | | Panel | Dropdown below cursor, var(--bg) bg, 1px border, 4px radius | | Max items | 8 visible, scroll for more | | Item height | 28px | | Active item | var(--accent-bg) highlight | | Categories | Variables (with last value), Functions (with signature), Keywords, Units, Currencies | | Keyboard | ↑↓ to navigate, Tab/Enter to accept, Esc to dismiss | | Auto-dismiss | On cursor movement away | --- ## Page States | State | When | Behavior | |-------|------|----------| | **Active editing** | User is typing | Debounced eval (50ms). Results update. Auto-save (500ms). | | **Idle** | User paused | All results current. Document saved. | | **Read-only** | Template preview (future) | No cursor, no editing. Gray overlay on gutter. | | **Engine loading** | WASM initializing | Editor is fully editable. Results show "—" until engine ready. | | **Large document** | > 500 lines | Viewport rendering only (CodeMirror handles this). Performance warning in status bar if > 1000 lines. | --- ## Interactions | Action | Behavior | |--------|----------| | Type expression | Debounced eval → results update in 50ms | | Define variable (`x = 5`) | Variable registered, available for autocomplete on subsequent lines | | Reference variable | Autocomplete suggests matching variables with their current values | | Use aggregator (`sum`, `total`) | Aggregates all numeric results above (up to previous heading or empty line block) | | Line reference (`#3`) | References result of line 3 | | Comment (`// text`) | Line excluded from evaluation, styled as comment | | Heading (`# text`) | Section header, not evaluated, used for visual grouping and aggregator scoping | | Select text | Selection count shown in status bar | | Cmd/Ctrl+Z | Undo (per-document history preserved while tab is open) | | Cmd/Ctrl+Shift+Z | Redo | | Cmd/Ctrl+D | Duplicate current line | | Cmd/Ctrl+/ | Toggle comment on current line | | Alt+↑/↓ | Move line up/down | --- ## Technical Notes - **CodeMirror instance management:** One instance per active tab. Inactive tabs store EditorState (preserves undo history). On tab switch, create new EditorView with stored state. - **Eval debounce:** 50ms (current). Consider making configurable in settings (0–200ms range). - **Syntax highlighting performance:** StreamLanguage parser runs synchronously — fine for < 1000 lines. For very large documents, consider switching to Lezer grammar. - **Font scaling:** Expose font size setting (12–24px range) in settings. Current 15px is good default. Store in localStorage. - **Cross-platform:** CodeMirror handles keyboard differences (Cmd vs Ctrl). Same extension stack works everywhere via WASM. --- ## Open Questions | # | Question | Context | Status | |---|----------|---------|--------| | 1 | Should headings have extra top margin? | Creates visual sections but breaks 1:1 line alignment with results panel | 🟡 In Discussion — likely yes, results panel adjusts | | 2 | Should comments skip zebra striping? | Makes them more visually distinct but breaks the pattern | 🔴 Open | | 3 | Font size as user preference? | 12–24px range slider in settings | 🟢 Resolved: Yes, default 15px | --- **Next Step:** → [Results Panel](../2.2-results-panel/2.2-results-panel.md) --- _Created using Whiteport Design Studio (WDS) methodology_