Electron Desktop App — Complete Implementation Plan

Project Context

What was pitched in Phase 1 (presentation)

What actually exists today

The Strategy (Option C)

Build the Electron + React frontend that was promised, but instead of re-implementing the AI in JavaScript, call the existing Python backend as a subprocess. This is architecturally honest — the “Local Backend (The Brain)” from the presentation runs as a Python process managed by Electron’s main process.

Deadline

2 weeks. Need a working demo + results slide for Phase 2 presentation.


Architecture Overview


┌──────────────────────────────────────────────────────┐

│ Electron App │

│ │

│ ┌─────────────────────────────────────────────────┐ │

│ │ React Frontend (Renderer) │ │

│ │ │ │

│ │ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │ │

│ │ │ Editor │ │ Mode │ │ Output Panel │ │ │

│ │ │ (input) │ │ Selector │ │ (result) │ │ │

│ │ └──────────┘ └──────────┘ └────────────────┘ │ │

│ │ ┌──────────────────────┐ ┌────────────────┐ │ │

│ │ │ Metrics Display │ │ Settings │ │ │

│ │ └──────────────────────┘ └────────────────┘ │ │

│ └─────────────────────────────────────────────────┘ │

│ │ IPC │

│ ┌─────────────────────────────────────────────────┐ │

│ │ Electron Main Process │ │

│ │ │ │

│ │ ┌──────────────────────────────────────┐ │ │

│ │ │ Python Bridge (child_process.spawn) │ │ │

│ │ │ Calls: python simplify_server.py │ │ │

│ │ └──────────────────────────────────────┘ │ │

│ └─────────────────────────────────────────────────┘ │

│ │ stdin/stdout (JSON) │

│ ┌─────────────────────────────────────────────────┐ │

│ │ Python Backend │ │

│ │ │ │

│ │ simplify_server.py (JSON stdin/stdout mode) │ │

│ │ ├── simplify.py (core logic) │ │

│ │ ├── dyslexia_mode.py │ │

│ │ ├── adhd_mode.py │ │

│ │ ├── autism_mode.py │ │

│ │ ├── utils.py │ │

│ │ └── t5-simplifier/ (fine-tuned model) │ │

│ └─────────────────────────────────────────────────┘ │

└──────────────────────────────────────────────────────┘

Communication Protocol


Directory Structure (Final)


chat editor ( mini project )/

├── electron-app/ # NEW — Electron desktop app

│ ├── package.json

│ ├── electron/

│ │ ├── main.js # Electron main process

│ │ ├── preload.js # Secure bridge (contextBridge)

│ │ └── python-bridge.js # Spawns & manages Python process

│ ├── src/

│ │ ├── App.jsx # Root React component

│ │ ├── App.css # Global styles

│ │ ├── index.jsx # React entry point

│ │ ├── index.html # HTML shell

│ │ ├── components/

│ │ │ ├── Editor.jsx # Text input area

│ │ │ ├── OutputPanel.jsx # Simplified text display

│ │ │ ├── ModeSelector.jsx # Dyslexia/ADHD/Autism toggle

│ │ │ ├── MetricsPanel.jsx # Before/after readability stats

│ │ │ ├── SettingsPanel.jsx # Font, theme, contrast settings

│ │ │ └── Toolbar.jsx # Top action bar

│ │ ├── styles/

│ │ │ ├── themes.css # Light/dark/high-contrast themes

│ │ │ └── fonts.css # OpenDyslexic font-face

│ │ └── assets/

│ │ └── fonts/

│ │ └── OpenDyslexic-Regular.otf

│ ├── tailwind.config.js

│ ├── postcss.config.js

│ └── vite.config.js # Bundler config

│

├── simplify.py # Existing — CLI tool (unchanged)

├── simplify_server.py # NEW — JSON stdin/stdout wrapper

├── dyslexia_mode.py # Existing

├── adhd_mode.py # Existing

├── autism_mode.py # Existing

├── utils.py # Existing

├── t5-simplifier/ # Existing — fine-tuned model

├── requirements.txt # Existing

└── docs/ # Existing


Detailed Implementation Steps

PHASE 1: Python Bridge Layer (Day 1)

Step 1.1: Create simplify_server.py

The existing simplify.py uses argparse and reads from files. The Electron app needs to send text directly (not via files). We create a thin JSON wrapper that:

  1. Reads JSON from stdin: {"text": "...", "mode": "dyslexia", "model": "small"}

  2. Calls the existing process_text() and compute_metrics() functions

  3. Writes JSON to stdout: {"result": "...", "metrics": {...}, "error": null}

  4. Stays alive for multiple requests (persistent process, not one-shot)

Protocol:

Why a persistent process? Loading the T5 model takes 5-10 seconds. We load once and keep the process alive, so subsequent simplifications are instant.

File: simplify_server.py


#!/usr/bin/env python3

"""JSON stdin/stdout server for Electron bridge."""

import sys

import json

  

# Reuse existing imports from simplify.py

from simplify import process_text, _select_model, _load_model

from utils import compute_metrics

  

def  handle_request(request):

action = request.get("action",  "simplify")

  

if action ==  "ping":

return  {"status":  "ready"}

  

if action ==  "quit":

sys.exit(0)

  

if action ==  "simplify":

text = request.get("text",  "")

mode = request.get("mode",  "dyslexia")

model_choice = request.get("model",  "small")

  

if  not text.strip():

return  {"error":  "No text provided",  "result":  "",  "metrics":  None}

  

try:

model_name =  _select_model(model_choice, text)

result =  process_text(text, mode, model_name)

metrics =  compute_metrics(text, result)

return  {"result": result,  "metrics": metrics,  "error":  None}

except  Exception  as e:

return  {"error":  str(e),  "result":  "",  "metrics":  None}

  

return  {"error":  f"Unknown action: {action}"}

  

def  main():

# Pre-load model on startup

_load_model("./t5-simplifier")

# Signal ready

print(json.dumps({"status":  "ready"}),  flush=True)

  

for line in sys.stdin:

line = line.strip()

if  not line:

continue

try:

request = json.loads(line)

response =  handle_request(request)

except json.JSONDecodeError:

response =  {"error":  "Invalid JSON"}

print(json.dumps(response),  flush=True)

  

if __name__ ==  "__main__":

main()

Step 1.2: Test the bridge independently


# Terminal test (type JSON, get JSON back):

echo  '{"action":"ping"}'  | python simplify_server.py

echo  '{"text":"The treaty was signed in 1648 and ended the war.","mode":"dyslexia"}'  | python simplify_server.py


PHASE 2: Electron Scaffold (Day 2-3)

Step 2.1: Initialize the project


mkdir electron-app

cd  electron-app

npm init  -y

npm install  electron  --save-dev

npm install  react  react-dom

npm install  -D  vite  @vitejs/plugin-react

npm install  -D  tailwindcss  @tailwindcss/vite

npm install  -D  concurrently

Step 2.2: Create electron/main.js

The main process:

  1. Creates a BrowserWindow

  2. Spawns the Python process via python-bridge.js

  3. Sets up IPC handlers so the renderer can send simplify requests

  4. Loads the React app from Vite’s dev server (dev) or built files (prod)


const  {  app,  BrowserWindow,  ipcMain  }  =  require('electron');

const  path  =  require('path');

const  {  PythonBridge  }  =  require('./python-bridge');

  

let  mainWindow;

let  pythonBridge;

  

function  createWindow()  {

mainWindow  =  new  BrowserWindow({

width:  1200,

height:  800,

webPreferences: {

preload:  path.join(__dirname,  'preload.js'),

contextIsolation:  true,

nodeIntegration:  false,

},

});

  

// Dev: load from Vite server. Prod: load built files.

if (process.env.NODE_ENV  ===  'development') {

mainWindow.loadURL('http://localhost:5173');

} else {

mainWindow.loadFile(path.join(__dirname,  '../dist/index.html'));

}

}

  

app.whenReady().then(async  ()  =>  {

// Start Python backend

pythonBridge  =  new  PythonBridge();

await  pythonBridge.start();

  

createWindow();

  

// IPC: renderer asks to simplify text

ipcMain.handle('simplify',  async (event,  {  text,  mode,  model  }) => {

return  pythonBridge.send({ action:  'simplify',  text,  mode,  model });

});

  

// IPC: renderer asks for ping/health check

ipcMain.handle('ping',  async () => {

return  pythonBridge.send({ action:  'ping' });

});

});

  

app.on('window-all-closed',  ()  =>  {

pythonBridge?.stop();

app.quit();

});

Step 2.3: Create electron/python-bridge.js

Manages the Python subprocess lifecycle:


const  {  spawn  }  =  require('child_process');

const  path  =  require('path');

  

class PythonBridge {

constructor()  {

this.process  =  null;

this.pending  =  new  Map();  // id -> {resolve, reject}

this.requestId  =  0;

this.buffer  =  '';

}

  

start()  {

return  new  Promise((resolve,  reject) => {

// Path to Python backend (parent of electron-app/)

const  backendDir  =  path.join(__dirname,  '..',  '..');

const  pythonScript  =  path.join(backendDir,  'simplify_server.py');

  

this.process  =  spawn('python', [pythonScript], {

cwd:  backendDir,

stdio: ['pipe',  'pipe',  'pipe'],

});

  

// Wait for the "ready" signal

const  onFirstLine  = (data) => {

const  line  =  data.toString().trim();

try {

const  msg  =  JSON.parse(line);

if (msg.status  ===  'ready') {

// Now set up the normal data handler

this.process.stdout.removeListener('data',  onFirstLine);

this.process.stdout.on('data', (d) =>  this._onData(d));

resolve();

}

} catch (e) {

// Not JSON yet, ignore (could be model loading logs)

}

};

this.process.stdout.on('data',  onFirstLine);

  

this.process.stderr.on('data', (data) => {

// Suppress Python warnings/loading messages

// Could log to file if needed for debugging

});

  

this.process.on('error',  reject);

  

// Timeout after 60s (model loading can take a while first time)

setTimeout(() =>  reject(new  Error('Python startup timeout')),  60000);

});

}

  

send(request)  {

return  new  Promise((resolve,  reject) => {

const  id  =  ++this.requestId;

this.pending.set(id, { resolve,  reject });

  

const  payload  =  JSON.stringify({ ...request,  _id:  id }) +  '\n';

this.process.stdin.write(payload);

  

// Timeout per request

setTimeout(() => {

if (this.pending.has(id)) {

this.pending.delete(id);

reject(new  Error('Request timeout'));

}

},  30000);

});

}

  

_onData(data)  {

this.buffer  +=  data.toString();

const  lines  =  this.buffer.split('\n');

this.buffer  =  lines.pop();  // Keep incomplete line in buffer

  

for (const  line  of  lines) {

if (!line.trim()) continue;

try {

const  response  =  JSON.parse(line);

// Resolve the oldest pending request

const  [firstId]  =  this.pending.keys();

if (firstId  !==  undefined) {

const  {  resolve  }  =  this.pending.get(firstId);

this.pending.delete(firstId);

resolve(response);

}

} catch (e) {

// Non-JSON output, ignore

}

}

}

  

stop()  {

if (this.process) {

try {

this.process.stdin.write(JSON.stringify({ action:  'quit' }) +  '\n');

} catch (e) {}

setTimeout(() =>  this.process?.kill(),  2000);

}

}

}

  

module.exports  =  { PythonBridge };

Step 2.4: Create electron/preload.js

Secure bridge between renderer (React) and main process:


const  {  contextBridge,  ipcRenderer  }  =  require('electron');

  

contextBridge.exposeInMainWorld('api',  {

simplify:  (text,  mode,  model)  =>

ipcRenderer.invoke('simplify',  { text, mode, model }),

ping:  ()  =>

ipcRenderer.invoke('ping'),

});


PHASE 3: React UI — Core Layout (Day 3-5)

This is where Abishek’s Google Stitch design comes in. The UI components below define the structure and logic — styling/layout will be adapted to match the Stitch design.

Step 3.1: Layout concept


┌─────────────────────────────────────────────────────────┐

│ Toolbar: [Mode: Dyslexia ▾] [Simplify ▶] [⚙ Settings] │

├────────────────────────────┬────────────────────────────┤

│ │ │

│ INPUT PANEL │ OUTPUT PANEL │

│ │ │

│ (Textarea or rich editor) │ (Formatted result) │

│ │ │

│ Type or paste your │ Simplified text appears │

│ complex text here... │ here after clicking │

│ │ "Simplify" │

│ │ │

├────────────────────────────┴────────────────────────────┤

│ METRICS BAR │

│ Words: 45 → 28 (-38%) | Sentences: 3 → 5 | FRE: +17 │

└─────────────────────────────────────────────────────────┘

Step 3.2: Components breakdown

App.jsx — Root. Manages state: inputText, outputText, mode, metrics, isLoading, settings (theme, font).

Toolbar.jsx — Mode selector dropdown, “Simplify” button, settings gear icon. The “Simplify” button calls window.api.simplify(text, mode, model).

Editor.jsx — Left panel. A <textarea> (or contenteditable div) for input. Could later be upgraded to Lexical editor. Shows placeholder text.

OutputPanel.jsx — Right panel. Displays the simplified result. Applies:

MetricsPanel.jsx — Bottom bar. Shows word count change, sentence length change, Flesch score change. Color-coded: green = improvement, red = worse.

SettingsPanel.jsx — Slide-out or modal. Controls:

Step 3.3: Core state flow


User types text in Editor

↓

User selects mode (Dyslexia/ADHD/Autism)

↓

User clicks "Simplify"

↓

App.jsx sets isLoading = true

↓

window.api.simplify(text, mode, "small")

↓ (IPC to main process → stdin to Python → stdout back)

Response: { result, metrics, error }

↓

App.jsx sets outputText, metrics, isLoading = false

↓

OutputPanel renders the result with mode-appropriate formatting

MetricsPanel shows the before/after numbers


PHASE 4: Accessibility Features (Day 5-7)

These are the specific features shown in the Phase 1 presentation that make this more than just “a text simplifier.”

Step 4.1: OpenDyslexic font

Step 4.2: High Contrast Mode (WCAG AAA)

Three themes:

Light (default):

Dark:

High Contrast (WCAG AAA — 7:1 ratio minimum):

Step 4.3: Cognitive Focus Mode

From the Phase 1 results slide — highlights the current sentence/paragraph being read:

Step 4.4: Font size control


PHASE 5: Polish & Results (Day 7-10)

Step 5.1: Loading state

Step 5.2: Error handling

Step 5.3: Package.json scripts


{

"scripts":  {

"dev":  "concurrently \"vite\"  \"electron .\"",

"build":  "vite build && electron-builder",

"start":  "electron ."

}

}

Step 5.4: Results slide screenshots

Take screenshots of:

  1. Main view — input + output side by side with metrics

  2. High Contrast mode — matching Phase 1 slide

  3. Cognitive Focus mode — matching Phase 1 slide

  4. OpenDyslexic font — showing the font change

  5. All three modes — dyslexia/ADHD/autism output comparison


PHASE 6: Documentation Updates (Day 10-12)

Step 6.1: Update docs/design.md

Step 6.2: Update docs/paper.tex

Step 6.3: Update project_explanation.md

Step 6.4: Update docs/design.md T5 conditioning note


Risk Assessment

| Risk | Likelihood | Mitigation |

|------|-----------|------------|

| Python path issues on different machines | Medium | Use python3 fallback, allow config in settings |

| Model loading too slow (10s+ wait) | Medium | Show loading screen, pre-warm on app start |

| Electron + Vite setup issues | Low | Well-documented stack, many examples |

| Google Stitch design → code mismatch | Medium | Stitch gives HTML/CSS, adapt to React components |

| 2-week deadline tight | Medium | Prioritize working demo over polish. Core: input→simplify→output. Everything else is bonus. |


Minimum Viable Demo (if running out of time)

If by day 10 things are behind schedule, the absolute minimum for a results slide is:

  1. ✅ Electron window opens

  2. ✅ Text input area works

  3. ✅ Mode selector works

  4. ✅ “Simplify” button calls Python and shows result

  5. ✅ Metrics display

  6. ✅ One accessibility feature (OpenDyslexic font OR high contrast)

This is enough for a convincing results screenshot. Focus mode and settings panel are bonus.


Implementation Order (What I will code)

  1. simplify_server.py — Python JSON bridge

  2. electron/main.js, preload.js, python-bridge.js — Electron core

  3. src/App.jsx — React shell with state management

  4. src/components/Editor.jsx — Input panel

  5. src/components/OutputPanel.jsx — Output panel

  6. src/components/ModeSelector.jsx — Mode toggle

  7. src/components/Toolbar.jsx — Top bar

  8. src/components/MetricsPanel.jsx — Stats bar

  9. CSS themes (light/dark/high-contrast)

  10. OpenDyslexic font integration

  11. src/components/SettingsPanel.jsx — Settings

  12. Cognitive Focus Mode (if time)

Abishek handles: UI design via Google Stitch → provides the visual layout/CSS that gets integrated into the React components above.# Electron Desktop App — Complete Implementation Plan

Project Context

What was pitched in Phase 1 (presentation)

What actually exists today

The Strategy (Option C)

Build the Electron + React frontend that was promised, but instead of re-implementing the AI in JavaScript, call the existing Python backend as a subprocess. This is architecturally honest — the “Local Backend (The Brain)” from the presentation runs as a Python process managed by Electron’s main process.

Deadline

2 weeks. Need a working demo + results slide for Phase 2 presentation.


Architecture Overview


┌──────────────────────────────────────────────────────┐

│ Electron App │

│ │

│ ┌─────────────────────────────────────────────────┐ │

│ │ React Frontend (Renderer) │ │

│ │ │ │

│ │ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │ │

│ │ │ Editor │ │ Mode │ │ Output Panel │ │ │

│ │ │ (input) │ │ Selector │ │ (result) │ │ │

│ │ └──────────┘ └──────────┘ └────────────────┘ │ │

│ │ ┌──────────────────────┐ ┌────────────────┐ │ │

│ │ │ Metrics Display │ │ Settings │ │ │

│ │ └──────────────────────┘ └────────────────┘ │ │

│ └─────────────────────────────────────────────────┘ │

│ │ IPC │

│ ┌─────────────────────────────────────────────────┐ │

│ │ Electron Main Process │ │

│ │ │ │

│ │ ┌──────────────────────────────────────┐ │ │

│ │ │ Python Bridge (child_process.spawn) │ │ │

│ │ │ Calls: python simplify_server.py │ │ │

│ │ └──────────────────────────────────────┘ │ │

│ └─────────────────────────────────────────────────┘ │

│ │ stdin/stdout (JSON) │

│ ┌─────────────────────────────────────────────────┐ │

│ │ Python Backend │ │

│ │ │ │

│ │ simplify_server.py (JSON stdin/stdout mode) │ │

│ │ ├── simplify.py (core logic) │ │

│ │ ├── dyslexia_mode.py │ │

│ │ ├── adhd_mode.py │ │

│ │ ├── autism_mode.py │ │

│ │ ├── utils.py │ │

│ │ └── t5-simplifier/ (fine-tuned model) │ │

│ └─────────────────────────────────────────────────┘ │

└──────────────────────────────────────────────────────┘

Communication Protocol


Directory Structure (Final)


chat editor ( mini project )/

├── electron-app/ # NEW — Electron desktop app

│ ├── package.json

│ ├── electron/

│ │ ├── main.js # Electron main process

│ │ ├── preload.js # Secure bridge (contextBridge)

│ │ └── python-bridge.js # Spawns & manages Python process

│ ├── src/

│ │ ├── App.jsx # Root React component

│ │ ├── App.css # Global styles

│ │ ├── index.jsx # React entry point

│ │ ├── index.html # HTML shell

│ │ ├── components/

│ │ │ ├── Editor.jsx # Text input area

│ │ │ ├── OutputPanel.jsx # Simplified text display

│ │ │ ├── ModeSelector.jsx # Dyslexia/ADHD/Autism toggle

│ │ │ ├── MetricsPanel.jsx # Before/after readability stats

│ │ │ ├── SettingsPanel.jsx # Font, theme, contrast settings

│ │ │ └── Toolbar.jsx # Top action bar

│ │ ├── styles/

│ │ │ ├── themes.css # Light/dark/high-contrast themes

│ │ │ └── fonts.css # OpenDyslexic font-face

│ │ └── assets/

│ │ └── fonts/

│ │ └── OpenDyslexic-Regular.otf

│ ├── tailwind.config.js

│ ├── postcss.config.js

│ └── vite.config.js # Bundler config

│

├── simplify.py # Existing — CLI tool (unchanged)

├── simplify_server.py # NEW — JSON stdin/stdout wrapper

├── dyslexia_mode.py # Existing

├── adhd_mode.py # Existing

├── autism_mode.py # Existing

├── utils.py # Existing

├── t5-simplifier/ # Existing — fine-tuned model

├── requirements.txt # Existing

└── docs/ # Existing


Detailed Implementation Steps

PHASE 1: Python Bridge Layer (Day 1)

Step 1.1: Create simplify_server.py

The existing simplify.py uses argparse and reads from files. The Electron app needs to send text directly (not via files). We create a thin JSON wrapper that:

  1. Reads JSON from stdin: {"text": "...", "mode": "dyslexia", "model": "small"}

  2. Calls the existing process_text() and compute_metrics() functions

  3. Writes JSON to stdout: {"result": "...", "metrics": {...}, "error": null}

  4. Stays alive for multiple requests (persistent process, not one-shot)

Protocol:

Why a persistent process? Loading the T5 model takes 5-10 seconds. We load once and keep the process alive, so subsequent simplifications are instant.

File: simplify_server.py


#!/usr/bin/env python3

"""JSON stdin/stdout server for Electron bridge."""

import sys

import json

  

# Reuse existing imports from simplify.py

from simplify import process_text, _select_model, _load_model

from utils import compute_metrics

  

def  handle_request(request):

action = request.get("action",  "simplify")

  

if action ==  "ping":

return  {"status":  "ready"}

  

if action ==  "quit":

sys.exit(0)

  

if action ==  "simplify":

text = request.get("text",  "")

mode = request.get("mode",  "dyslexia")

model_choice = request.get("model",  "small")

  

if  not text.strip():

return  {"error":  "No text provided",  "result":  "",  "metrics":  None}

  

try:

model_name =  _select_model(model_choice, text)

result =  process_text(text, mode, model_name)

metrics =  compute_metrics(text, result)

return  {"result": result,  "metrics": metrics,  "error":  None}

except  Exception  as e:

return  {"error":  str(e),  "result":  "",  "metrics":  None}

  

return  {"error":  f"Unknown action: {action}"}

  

def  main():

# Pre-load model on startup

_load_model("./t5-simplifier")

# Signal ready

print(json.dumps({"status":  "ready"}),  flush=True)

  

for line in sys.stdin:

line = line.strip()

if  not line:

continue

try:

request = json.loads(line)

response =  handle_request(request)

except json.JSONDecodeError:

response =  {"error":  "Invalid JSON"}

print(json.dumps(response),  flush=True)

  

if __name__ ==  "__main__":

main()

Step 1.2: Test the bridge independently


# Terminal test (type JSON, get JSON back):

echo  '{"action":"ping"}'  | python simplify_server.py

echo  '{"text":"The treaty was signed in 1648 and ended the war.","mode":"dyslexia"}'  | python simplify_server.py


PHASE 2: Electron Scaffold (Day 2-3)

Step 2.1: Initialize the project


mkdir electron-app

cd  electron-app

npm init  -y

npm install  electron  --save-dev

npm install  react  react-dom

npm install  -D  vite  @vitejs/plugin-react

npm install  -D  tailwindcss  @tailwindcss/vite

npm install  -D  concurrently

Step 2.2: Create electron/main.js

The main process:

  1. Creates a BrowserWindow

  2. Spawns the Python process via python-bridge.js

  3. Sets up IPC handlers so the renderer can send simplify requests

  4. Loads the React app from Vite’s dev server (dev) or built files (prod)


const  {  app,  BrowserWindow,  ipcMain  }  =  require('electron');

const  path  =  require('path');

const  {  PythonBridge  }  =  require('./python-bridge');

  

let  mainWindow;

let  pythonBridge;

  

function  createWindow()  {

mainWindow  =  new  BrowserWindow({

width:  1200,

height:  800,

webPreferences: {

preload:  path.join(__dirname,  'preload.js'),

contextIsolation:  true,

nodeIntegration:  false,

},

});

  

// Dev: load from Vite server. Prod: load built files.

if (process.env.NODE_ENV  ===  'development') {

mainWindow.loadURL('http://localhost:5173');

} else {

mainWindow.loadFile(path.join(__dirname,  '../dist/index.html'));

}

}

  

app.whenReady().then(async  ()  =>  {

// Start Python backend

pythonBridge  =  new  PythonBridge();

await  pythonBridge.start();

  

createWindow();

  

// IPC: renderer asks to simplify text

ipcMain.handle('simplify',  async (event,  {  text,  mode,  model  }) => {

return  pythonBridge.send({ action:  'simplify',  text,  mode,  model });

});

  

// IPC: renderer asks for ping/health check

ipcMain.handle('ping',  async () => {

return  pythonBridge.send({ action:  'ping' });

});

});

  

app.on('window-all-closed',  ()  =>  {

pythonBridge?.stop();

app.quit();

});

Step 2.3: Create electron/python-bridge.js

Manages the Python subprocess lifecycle:


const  {  spawn  }  =  require('child_process');

const  path  =  require('path');

  

class PythonBridge {

constructor()  {

this.process  =  null;

this.pending  =  new  Map();  // id -> {resolve, reject}

this.requestId  =  0;

this.buffer  =  '';

}

  

start()  {

return  new  Promise((resolve,  reject) => {

// Path to Python backend (parent of electron-app/)

const  backendDir  =  path.join(__dirname,  '..',  '..');

const  pythonScript  =  path.join(backendDir,  'simplify_server.py');

  

this.process  =  spawn('python', [pythonScript], {

cwd:  backendDir,

stdio: ['pipe',  'pipe',  'pipe'],

});

  

// Wait for the "ready" signal

const  onFirstLine  = (data) => {

const  line  =  data.toString().trim();

try {

const  msg  =  JSON.parse(line);

if (msg.status  ===  'ready') {

// Now set up the normal data handler

this.process.stdout.removeListener('data',  onFirstLine);

this.process.stdout.on('data', (d) =>  this._onData(d));

resolve();

}

} catch (e) {

// Not JSON yet, ignore (could be model loading logs)

}

};

this.process.stdout.on('data',  onFirstLine);

  

this.process.stderr.on('data', (data) => {

// Suppress Python warnings/loading messages

// Could log to file if needed for debugging

});

  

this.process.on('error',  reject);

  

// Timeout after 60s (model loading can take a while first time)

setTimeout(() =>  reject(new  Error('Python startup timeout')),  60000);

});

}

  

send(request)  {

return  new  Promise((resolve,  reject) => {

const  id  =  ++this.requestId;

this.pending.set(id, { resolve,  reject });

  

const  payload  =  JSON.stringify({ ...request,  _id:  id }) +  '\n';

this.process.stdin.write(payload);

  

// Timeout per request

setTimeout(() => {

if (this.pending.has(id)) {

this.pending.delete(id);

reject(new  Error('Request timeout'));

}

},  30000);

});

}

  

_onData(data)  {

this.buffer  +=  data.toString();

const  lines  =  this.buffer.split('\n');

this.buffer  =  lines.pop();  // Keep incomplete line in buffer

  

for (const  line  of  lines) {

if (!line.trim()) continue;

try {

const  response  =  JSON.parse(line);

// Resolve the oldest pending request

const  [firstId]  =  this.pending.keys();

if (firstId  !==  undefined) {

const  {  resolve  }  =  this.pending.get(firstId);

this.pending.delete(firstId);

resolve(response);

}

} catch (e) {

// Non-JSON output, ignore

}

}

}

  

stop()  {

if (this.process) {

try {

this.process.stdin.write(JSON.stringify({ action:  'quit' }) +  '\n');

} catch (e) {}

setTimeout(() =>  this.process?.kill(),  2000);

}

}

}

  

module.exports  =  { PythonBridge };

Step 2.4: Create electron/preload.js

Secure bridge between renderer (React) and main process:


const  {  contextBridge,  ipcRenderer  }  =  require('electron');

  

contextBridge.exposeInMainWorld('api',  {

simplify:  (text,  mode,  model)  =>

ipcRenderer.invoke('simplify',  { text, mode, model }),

ping:  ()  =>

ipcRenderer.invoke('ping'),

});


PHASE 3: React UI — Core Layout (Day 3-5)

This is where Abishek’s Google Stitch design comes in. The UI components below define the structure and logic — styling/layout will be adapted to match the Stitch design.

Step 3.1: Layout concept


┌─────────────────────────────────────────────────────────┐

│ Toolbar: [Mode: Dyslexia ▾] [Simplify ▶] [⚙ Settings] │

├────────────────────────────┬────────────────────────────┤

│ │ │

│ INPUT PANEL │ OUTPUT PANEL │

│ │ │

│ (Textarea or rich editor) │ (Formatted result) │

│ │ │

│ Type or paste your │ Simplified text appears │

│ complex text here... │ here after clicking │

│ │ "Simplify" │

│ │ │

├────────────────────────────┴────────────────────────────┤

│ METRICS BAR │

│ Words: 45 → 28 (-38%) | Sentences: 3 → 5 | FRE: +17 │

└─────────────────────────────────────────────────────────┘

Step 3.2: Components breakdown

App.jsx — Root. Manages state: inputText, outputText, mode, metrics, isLoading, settings (theme, font).

Toolbar.jsx — Mode selector dropdown, “Simplify” button, settings gear icon. The “Simplify” button calls window.api.simplify(text, mode, model).

Editor.jsx — Left panel. A <textarea> (or contenteditable div) for input. Could later be upgraded to Lexical editor. Shows placeholder text.

OutputPanel.jsx — Right panel. Displays the simplified result. Applies:

MetricsPanel.jsx — Bottom bar. Shows word count change, sentence length change, Flesch score change. Color-coded: green = improvement, red = worse.

SettingsPanel.jsx — Slide-out or modal. Controls:

Step 3.3: Core state flow


User types text in Editor

↓

User selects mode (Dyslexia/ADHD/Autism)

↓

User clicks "Simplify"

↓

App.jsx sets isLoading = true

↓

window.api.simplify(text, mode, "small")

↓ (IPC to main process → stdin to Python → stdout back)

Response: { result, metrics, error }

↓

App.jsx sets outputText, metrics, isLoading = false

↓

OutputPanel renders the result with mode-appropriate formatting

MetricsPanel shows the before/after numbers


PHASE 4: Accessibility Features (Day 5-7)

These are the specific features shown in the Phase 1 presentation that make this more than just “a text simplifier.”

Step 4.1: OpenDyslexic font

Step 4.2: High Contrast Mode (WCAG AAA)

Three themes:

Light (default):

Dark:

High Contrast (WCAG AAA — 7:1 ratio minimum):

Step 4.3: Cognitive Focus Mode

From the Phase 1 results slide — highlights the current sentence/paragraph being read:

Step 4.4: Font size control


PHASE 5: Polish & Results (Day 7-10)

Step 5.1: Loading state

Step 5.2: Error handling

Step 5.3: Package.json scripts


{

"scripts":  {

"dev":  "concurrently \"vite\"  \"electron .\"",

"build":  "vite build && electron-builder",

"start":  "electron ."

}

}

Step 5.4: Results slide screenshots

Take screenshots of:

  1. Main view — input + output side by side with metrics

  2. High Contrast mode — matching Phase 1 slide

  3. Cognitive Focus mode — matching Phase 1 slide

  4. OpenDyslexic font — showing the font change

  5. All three modes — dyslexia/ADHD/autism output comparison


PHASE 6: Documentation Updates (Day 10-12)

Step 6.1: Update docs/design.md

Step 6.2: Update docs/paper.tex

Step 6.3: Update project_explanation.md

Step 6.4: Update docs/design.md T5 conditioning note


Risk Assessment

| Risk | Likelihood | Mitigation |

|------|-----------|------------|

| Python path issues on different machines | Medium | Use python3 fallback, allow config in settings |

| Model loading too slow (10s+ wait) | Medium | Show loading screen, pre-warm on app start |

| Electron + Vite setup issues | Low | Well-documented stack, many examples |

| Google Stitch design → code mismatch | Medium | Stitch gives HTML/CSS, adapt to React components |

| 2-week deadline tight | Medium | Prioritize working demo over polish. Core: input→simplify→output. Everything else is bonus. |


Minimum Viable Demo (if running out of time)

If by day 10 things are behind schedule, the absolute minimum for a results slide is:

  1. ✅ Electron window opens

  2. ✅ Text input area works

  3. ✅ Mode selector works

  4. ✅ “Simplify” button calls Python and shows result

  5. ✅ Metrics display

  6. ✅ One accessibility feature (OpenDyslexic font OR high contrast)

This is enough for a convincing results screenshot. Focus mode and settings panel are bonus.


Implementation Order (What I will code)

  1. simplify_server.py — Python JSON bridge

  2. electron/main.js, preload.js, python-bridge.js — Electron core

  3. src/App.jsx — React shell with state management

  4. src/components/Editor.jsx — Input panel

  5. src/components/OutputPanel.jsx — Output panel

  6. src/components/ModeSelector.jsx — Mode toggle

  7. src/components/Toolbar.jsx — Top bar

  8. src/components/MetricsPanel.jsx — Stats bar

  9. CSS themes (light/dark/high-contrast)

  10. OpenDyslexic font integration

  11. src/components/SettingsPanel.jsx — Settings

  12. Cognitive Focus Mode (if time)

Abishek handles: UI design via Google Stitch → provides the visual layout/CSS that gets integrated into the React components above.