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.
Range.select() API and never
edits the document. If the exact wording can no longer be found (e.g. the
script was edited after the last check), the whole paragraph is selected
instead and the status line tells you so — just click Refresh and try
again.??,
.. 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).-, *, •) or numbered patterns at
the start of a line, since scripts should be read-aloud prose.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.
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
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.
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:
activeTab
permission — nothing runs automatically or in the background, and Chrome
doesn’t even show a host-permission warning on install).ScriptCheckerRules.checkDocument() function from src/rules/ruleEngine.js,
then filters the results down to the three categories above.textContent and toggles a temporary
CSS class for highlighting, plus a CSS margin on the page while the panel
is open. It never edits the page or saves anything back to Canvas.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):
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).chrome://extensions, turn on Developer mode
(top-right toggle).chrome-extension/ folder in
this repo.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:
manifest-share.xml file you sent them.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 athttps://localhost:3000and is only useful on a machine that also has this repo checked out andnpm startrunning (see below).manifest-share.xmlis the one to actually hand out.
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:
idea-lab-canvas-editorial-checker-vX.Y.Z.zip
asset), ornpm run build:extension, then
zip up the chrome-extension/ folder.chrome://extensions → turn on Developer mode (top-right
toggle) → Load unpacked → select the unzipped folder.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.
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.)
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.
Start the local server:
npm start
This serves the project at https://localhost:3000 (leave it running).
Sideload the manifest using the shared folder method (the most reliable approach on Mac):
mkdir -p ~/Library/Containers/com.Microsoft.Word/Data/Documents/wef
cp manifest.xml ~/Library/Containers/com.Microsoft.Word/Data/Documents/wef/
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.
.dotm
macro templates and will never show an Office.js add-in.https://localhost:3000/src/taskpane/taskpane.html directly in a normal
browser tab first, accept any certificate warning there, then reopen the
task pane in Word. (This is only relevant to the local-dev manifest.xml
— manifest-share.xml, served over GitHub Pages with a real certificate,
doesn’t have this problem at all.)ReadDocument
permission only. No code path in this version writes to the Word
document.office.js once and
reference it from assets/ instead of the CDN URL in taskpane.html.)src/rules/ruleEngine.js has no
dependency on Office.js or the DOM — it’s a pure module that takes an
array of paragraph strings/objects and returns issues, so it is fully
unit-testable and reusable.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.