• Гильмуллин Руслан Ниязович's avatar
    Rewrite to Svelte 5 + TypeScript
    · ea31182e
    Full rewrite of the demo's main thread from vanilla JS classes-with-DOM to
    Svelte 5 components (runes mode), with a typed worker contract. Driven by an
    internal code-quality audit that flagged a 380-line god function, dual sources
    of truth for button-disabled state, drift between worker request/response
    shapes, and a silent mobile belt-width bug.
    
    Structural changes:
    
    - Typed worker contract via discriminated unions (lib/types.ts). Single
      canonical Command shape — symbol === null means "keep" everywhere — replacing
      the dual KEEP-Symbol vs null impedance mismatch.
    - MachineTab.svelte orchestrates per-engine state. executionMode is $state and
      every UI flag (panel/apply/take-control visibility, button-disabled) is a
      $derived line. The old applyMode switch and per-handler reset dance are gone.
    - One <MachineTab engine={...}> instantiated per active tab; switching tabs
      unmounts/remounts (via {#key activeEngine}) which cleanly tears down the
      worker, timers, and CodeMirror instance.
    - Editor lazy-loaded as a separate Vite chunk (~540 KB / 180 KB gz) so initial
      paint ships ~24 KB gz instead of ~200 KB gz; tape + control panel are visible
      immediately while CodeMirror loads in parallel.
    - Lezer-based syntax preflight in the editor (markers before Load) plus
      boost-99 priority for machine-namespace identifiers in autocomplete.
    - popstate listener so browser back/forward updates the active tab.
    - Mobile belt width fixed: CSS owns geometry, JS only owns indexing counts.
      Three responsive tiers (≤480px / ≤768px / desktop) replace the single
      phone-tuned breakpoint.
    - Surface tokens (--surface-*, --editor-bg) consolidate the duplicated
      panel-recipe CSS and align the log panel with CodeMirror's oneDark surface.
    - Favicon repainted as a head cell (yellow doubled border + ▲ glyph below).
    
    Tooling: TypeScript (strict), ESLint flat config (typescript-eslint +
    eslint-plugin-svelte), svelte-check, Vite 5 + @sveltejs/vite-plugin-svelte 4,
    svelte-codemirror-editor for the editor wrapper. Prettier and Vitest are
    deferred — tests can land in a follow-up.
    
    Multi-tape Turing display is tracked as
    https://github.com/mellonis/machines-demo/issues/1; the worker now asserts
    single-tape explicitly rather than silently dropping tapes ≥ 1.
    
    Note: workerLive isn't reset on the worker-timeout path. Currently masked
    because halted=true dominates the disabled-state gates; worth re-checking if
    those gates ever loosen.
    ea31182e