idea-lab-script-checker

IDEA Lab Script Checker

A Word (Office.js) task pane add-in for the IDEA Lab media team. It runs a last-hurdle, read-only quick check of video scripts received from module leaders/learning designers, before the scripts go into production.

⚠️ This is a quick checker, not a substitute for editorial or subject review. It is aimed at media team members who are not subject or editorial specialists. It flags possible issues for a human to glance over — it never edits the document automatically.

What it does

Rule categories

  1. Obvious errors — doubled words, repeated/stray punctuation (??, .. that isn’t a genuine ... ellipsis, a stray space before a comma), unmatched quotation marks/brackets, and a small, clearly-labelled list of “possible typos” (not a full spellcheck).
  2. Read-aloud flow — sentences over ~30 words (flagged with the word count), overall pacing vs. the ~125–150 words-per-minute / ~400–750 word guidance for a 3–5 minute video (informational), common AI-sounding filler phrases (“it’s important to note”, “delve into”, “in conclusion”, etc.), and an informational Flesch-Kincaid-style readability estimate.
  3. Bullet points in scripts — any bulleted/numbered list in the script body, detected via Word’s own list-paragraph metadata and via markdown-style bullet characters (-, *, •) or numbered patterns at the start of a line, since scripts should be read-aloud prose.
  4. House style & editorial compliance — hyphenation (e.g. “cost-effective”, “part-time”), en/em dash usage, forward-slash spacing, Latin abbreviations (e.g./i.e./etc.), number style (spell out 1–10 in prose, never start a sentence with a digit), percentage-form consistency, date formatting, British vs. American spelling, practice/practise, “vs.”, ampersands, the Oxford comma (low-confidence note), title capitalisation, “Prof”/”Dr.”/”Mr.”/”Mrs.”/”Syndicate group”, and bullet/list formatting rules (stem colon, capitalisation, full-stop consistency) for any lists intentionally kept.
  5. Session/activity numbering — every “session N” / “activity N.N” reference is surfaced in its own category so the media team can see at a glance what might break if the module is reordered later. This covers both numeral forms (“session 5”) and spelled-out number words (“Session one”, “session five”) — numeral forms and incorrectly-cased word forms are flagged as style warnings (should be lowercase spelled-out words, e.g. “session five”), while correctly-formatted word references are still surfaced as a lower-severity informational note, since any specific session/activity reference is worth a second glance before production in case the module is reordered later.
  6. Inclusivity & diversity language — a lookup table of terms to avoid (with suggested alternatives), plus a low-confidence heuristic for generic gendered pronouns following a non-specific subject (e.g. “a student… he…”).

All rules are implemented as pure, framework-agnostic JavaScript functions in src/rules/ruleEngine.js, independent of Office.js, so they can be unit tested without Word running and reused elsewhere.

Project structure

idea-lab-script-checker/
├── manifest.xml                 # Office Add-in manifest (sideloading)
├── server.js                    # Minimal local HTTPS static server (dev only)
├── package.json
├── src/
│   ├── rules/
│   │   └── ruleEngine.js        # Pure rule-checking logic (no Office.js dependency)
│   ├── canvas/
│   │   └── htmlToParagraphs.js  # HTML -> paragraph converter for Canvas rich-text content
│   └── taskpane/
│       ├── taskpane.html
│       ├── taskpane.css
│       └── taskpane.js          # Office.js glue: reads doc, calls ruleEngine, renders UI
├── chrome-extension/            # Browser extension: run the same checks on Canvas LMS pages
│   ├── manifest.json
│   ├── background.js
│   ├── lib/ruleEngine.js        # auto-generated copy, see "Chrome extension" section below
│   ├── content/
│   │   ├── domExtractor.js
│   │   ├── panel.js
│   │   └── panel.css
│   └── icons/
├── scripts/
│   └── copy-rule-engine.js      # keeps chrome-extension/lib/ruleEngine.js in sync
├── tests/
│   ├── ruleEngine.test.js       # Vitest unit tests for the rule engine
│   └── htmlToParagraphs.test.js # Vitest unit tests for the Canvas HTML converter
└── assets/
    └── icon-32.png / icon-64.png / icon-80.png

Running the tests

npm install
npm test

This runs the Vitest suite (tests/ruleEngine.test.js and tests/htmlToParagraphs.test.js) covering realistic example scripts (clean scripts, and scripts deliberately containing each class of flagged issue) for every rule category above.

Chrome extension: IDEA Lab Canvas Editorial Checker

The same rule engine also ships as a small, dependency-free Chrome extension, the IDEA Lab Canvas Editorial Checker, so the media team can run an editorial pass directly on Canvas course content (Pages, Assignments, Discussion Topics, the Syllabus) — no API token, no server, no network calls at all. It’s the lowest-friction way to get this tool working against Canvas: it just reads whatever rich-text content is already rendered on the Canvas page you have open in the browser.

Scope — narrower than the Word add-in, by design: this tool is purely an editorial aid for course content, checked against the single House Style and Conventions Guide. It only shows:

Read-aloud flow, bullet-points-in-script, and session/activity numbering are intentionally excluded here — those checks are specific to video scripts (and the other two style documents), not general course content, and aren’t relevant to an editorial pass over a Canvas Page or Assignment.

How it works:

Keeping the panel open as you browse (optional, off by default): by default the panel only appears when you click the icon, and closes again if you navigate to a new page (a fresh content-script injection each time, the same explicit “click-to-run” model as the Word add-in). If you’d rather it stay open and automatically refresh its results every time you move to a new Canvas page, click “📌 Auto-open: off” in the panel’s header to turn it on for the current site:

Known limitation: it checks whatever is currently rendered on the page (a Page/Assignment/Discussion/Syllabus “view”, or the Syllabus). It does not yet reach inside the Rich Content Editor while you’re actively editing (TinyMCE’s edit iframe), and it checks one page at a time rather than bulk-scanning an entire course — view/publish the page first, then run the checker, as a last-hurdle editorial pass before sharing with students.

If you click the icon and nothing happens: Chrome never allows any extension to run on its own internal pages (chrome://..., a blank new tab, the Chrome Web Store, etc) — this is a Chrome-wide restriction, not a bug in the extension. The toolbar icon will briefly show a red “!” badge with an explanatory tooltip in that case. Navigate to the actual Canvas page you want to check first, then click the icon.

Installing it locally (unpacked, for now — not published to the Chrome Web Store):

  1. cd into the repo and run npm run build:extension (this copies the latest src/rules/ruleEngine.js into chrome-extension/lib/; re-run it any time the rule engine changes).
  2. In Chrome, go to chrome://extensions, turn on Developer mode (top-right toggle).
  3. Click Load unpacked and select the chrome-extension/ folder in this repo.
  4. Open a Canvas Page, Assignment, Discussion Topic, or Syllabus page, then click the IDEA Lab Canvas Editorial Checker icon in the toolbar to run a check. Click it again to close the panel.

By default the extension works on any page (it only activates when you click the icon), so there’s nothing Canvas-domain-specific to configure — if your institution’s Canvas uses a custom domain rather than *.instructure.com, it will still work, since activeTab grants access to whatever tab is currently active regardless of domain.

The add-in is hosted on GitHub Pages at:

https://aparry-idealab.github.io/idea-lab-script-checker/

This is kept in sync with the main branch — every push rebuilds it automatically within a minute or two, so updates reach everyone immediately with no reinstall needed.

To let a colleague use it, just send them manifest-share.xml (from the repo root) — it points at the GitHub Pages URL above rather than localhost, so they do not need Node.js, this repository, or a local dev server/certificate at all. They:

  1. Open Word (desktop or Word Online).
  2. Home tab → Add-ins → Upload My Add-in (on Word Online) or Home tab → Add-ins → More Add-ins → Developer Add-ins → Upload My Add-in (on Word desktop/Mac — this UI varies a bit by Word version and platform; see “Sideloading in Word on a Mac” below for the full set of menu paths we found work).
  3. Select the manifest-share.xml file you sent them.
  4. The “Check Script” button appears — click it to open the task pane.

For wider/automatic rollout across the whole team (no manual upload step per person at all), ask your Microsoft 365 administrator to deploy manifest-share.xml via Microsoft 365 admin center → Settings → Integrated apps (a.k.a. Centralized Deployment) — this requires tenant admin access but then every targeted user gets the add-in automatically.

manifest.xml (no suffix) is the local development manifest — it points at https://localhost:3000 and is only useful on a machine that also has this repo checked out and npm start running (see below). manifest-share.xml is the one to actually hand out.

Sharing the Chrome extension with colleagues

Unlike the Word add-in, an unpacked Chrome extension has no auto-updating hosted URL to just send someone — they need the extension’s files on disk and to load them via Developer mode. The easiest way for a small team:

  1. Download the extension as a zip. Either:
    • Grab the latest built zip from the repo’s Releases page (look for the most recent idea-lab-canvas-editorial-checker-vX.Y.Z.zip asset), or
    • Clone/download the repo yourself, run npm run build:extension, then zip up the chrome-extension/ folder.
  2. Send your colleague the zip file (email, Slack, shared drive — anything).
  3. They unzip it anywhere on their machine (anywhere is fine — just don’t delete/move the folder afterwards, Chrome keeps pointing at it).
  4. In Chrome: chrome://extensions → turn on Developer mode (top-right toggle) → Load unpacked → select the unzipped folder.
  5. Done — the icon appears in their toolbar immediately.

Updates: because this is an unpacked, unpublished extension, updates don’t roll out automatically — when the rule engine or extension changes, re-zip and re-share it, and each person clicks the reload icon on the extension’s card in chrome://extensions (or re-does “Load unpacked” if they replaced the folder).

If you want push-button updates for the whole team longer-term: publish it to the Chrome Web Store as an Unlisted item (not searchable publicly — only people with the direct link can install it). This costs a one-off $5 Chrome Web Store developer registration fee and goes through Google’s review process (usually hours to a few days), but after that, updates roll out to everyone automatically and nobody needs Developer mode turned on. Not set up yet — let me know if you’d like this done.

Sideloading in Word on a Mac (for local development)

Office Add-ins must be served over HTTPS with a certificate Word trusts — file:// URLs are not supported for the task pane. The included server.js uses office-addin-dev-certs to generate and trust a local development certificate, so you don’t need any external hosting. (This is only needed if you’re developing/testing changes locally — see “Sharing this with colleagues” above for the no-setup option everyone else should use.)

  1. Install dependencies and trust the local dev certificate (one-time):

    npm install
    npx office-addin-dev-certs install
    

    macOS will prompt you to add the certificate to your keychain — accept this so Word trusts https://localhost:3000.

  2. Start the local server:

    npm start
    

    This serves the project at https://localhost:3000 (leave it running).

  3. Sideload the manifest using the shared folder method (the most reliable approach on Mac):

    • Create a trusted catalog folder, e.g.:
      mkdir -p ~/Library/Containers/com.Microsoft.Word/Data/Documents/wef
      cp manifest.xml ~/Library/Containers/com.Microsoft.Word/Data/Documents/wef/
      
    • Open Word → Preferences → Ribbon & Toolbar → not here; instead go to the Insert tab → Add-ins → My Add-ins → the gear/”…” menu → Upload My Add-in, or, if your Word build already watches the shared folder automatically, the add-in should simply appear under My Add-ins → Shared Folder.
    • If prompted, trust the add-in.
  4. Open any .docx, go to the Insert tab (or wherever the add-in placed its button — “Script Checker” group, “Check Script” button), and click it to open the task pane. It auto-runs on load; use Refresh to re-run after editing the script.

If the shared-folder method isn’t picking up the manifest, the alternative is Word’s Upload My Add-in dialog (Insert → Add-ins → My Add-ins → “…” → Upload My Add-in) and point it directly at manifest.xml — this works the same way and avoids any folder-watching quirks on some Word builds.

Troubleshooting sideloading (found while testing on Word for Mac)

Design principles

Extending the rule engine

Add a new check as a small pure function in src/rules/ruleEngine.js that returns an array of issues built with the internal makeIssue(...) helper, then call it from checkDocument(...). Add a corresponding test case in tests/ruleEngine.test.js with both a clean example and a deliberately flagged example.