Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c3e0e03
docs(three-d-viewer): add SDD-0001 and ADR-0001 for interaction layer
erseco Jul 10, 2026
fb21e4f
feat(three-d-viewer): add versioned interaction schema and migration
erseco Jul 10, 2026
8c19867
feat(three-d-viewer): shared interaction runtime with renderer adapters
erseco Jul 10, 2026
644f5fd
feat(three-d-viewer): export interaction markup and runtime boot
erseco Jul 10, 2026
d721ecc
feat(three-d-viewer): interaction authoring UI and styles
erseco Jul 10, 2026
7f817e9
test(three-d-viewer): E2E for interactions; fix marker wipe on form c…
erseco Jul 10, 2026
b37309e
fix(three-d-viewer): harden interaction layer after adversarial review
erseco Jul 10, 2026
a55a32a
test(three-d-viewer): make interaction E2E robust to headless WebGL
erseco Jul 10, 2026
0386525
feat(three-d-viewer): make question markers SCORM-gradable
erseco Jul 10, 2026
7ef6bc7
build(idevices): reuse centralized TypeScript iDevice pipeline
claude Jul 30, 2026
5d957a1
refactor(three-d-viewer): migrate the iDevice to TypeScript
claude Jul 30, 2026
7be5f3c
test(three-d-viewer): port the suite to TypeScript and extend E2E cov…
claude Jul 30, 2026
fc0b0ed
docs(three-d-viewer): describe the TypeScript architecture
claude Jul 30, 2026
4ebb239
fix(export): keep generated source maps out of server-side export pac…
claude Jul 30, 2026
dc57c98
fix(three-d-viewer): restore editor animation playback and canvas tea…
claude Jul 30, 2026
d99ce97
fix(build): stop gitignore from swallowing iDevice src/runtime sources
claude Jul 30, 2026
313ce96
fix(build): build assets before the CI unit-test run
claude Jul 30, 2026
3b7d808
ci: re-run checks after cancelled workflow runs
erseco Aug 4, 2026
b9cb125
fix(build): exclude iDevice source maps from resource bundles after r…
erseco Aug 31, 2026
42e7b5c
Merge branch 'main' into refactor/three-d-viewer-typescript
erseco Aug 31, 2026
01d2a62
fix(three-d-viewer): bind pagehide instead of beforeunload
erseco Aug 31, 2026
f27a4af
fix(three-d-viewer): narrow pagehide handler before calling it
erseco Aug 31, 2026
89033e1
fix(scorm12): expect the TypeScript 3D Viewer IIFE in the package
erseco Aug 31, 2026
10505ad
Merge branch 'main' into refactor/three-d-viewer-typescript
erseco Sep 1, 2026
2b93afd
Merge branch 'main' into refactor/three-d-viewer-typescript
erseco Sep 2, 2026
03a3939
Merge branch 'main' into refactor/three-d-viewer-typescript
erseco Sep 3, 2026
882c8f2
Merge branch 'main' into refactor/three-d-viewer-typescript
erseco Sep 3, 2026
f0fcf8a
Merge branch 'main' into refactor/three-d-viewer-typescript
erseco Sep 3, 2026
5e29423
Merge remote-tracking branch 'ate/main' into refactor/three-d-viewer-…
erseco Sep 5, 2026
1844414
Merge branch 'main' into refactor/three-d-viewer-typescript
erseco Sep 6, 2026
58be762
Merge branch 'main' into refactor/three-d-viewer-typescript
erseco Sep 7, 2026
5e914bd
Merge branch 'main' into refactor/three-d-viewer-typescript
erseco Sep 8, 2026
949f1ee
Merge branch 'main' into refactor/three-d-viewer-typescript
erseco Sep 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .agents/skills/idevice/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ Creating or modifying interactive devices (iDevices) in `public/files/perm/idevi

**Reference iDevices** (well-tested, good to study): `checklist`, `rubric`, `geogebra-activity`

## TypeScript iDevices (`src/`)

An iDevice with a `src/` directory is a **TypeScript iDevice**: its
`edition/<name>.js` and `export/<name>.js` are GENERATED bundles (gitignored)
— never edit them; edit `src/` and rebuild. Convention and commands:

- `src/edition/index.ts` → `edition/<name>.js` (assigns `window.$exeDevice`);
`src/export/index.ts` → `export/<name>.js` (assigns the runtime global).
- Build/typecheck: `bun run bundle:idevices` / `bun run typecheck:idevices`
(central runner `scripts/build-idevices.ts`; `--only <name>`, `--watch`).
Run `make bundle` after src/ edits and BEFORE E2E, or the preview serves the
stale bundle from `public/bundles/idevices.zip`.
- Tests are colocated `*.spec.ts` (Vitest — `bun test` ignores `public/**`),
plus bundle-contract smoke tests over the compiled IIFEs.
- Deviations (custom bundle name, externals, minify) go in an optional
`build.config.json` — see `doc/development/idevices-typescript.md` and
ADR-2147-01. Reference implementations: `three-d-viewer` (full convention),
`slide` (manifest).

## Structure

```
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ jobs:
- name: Build all assets once
run: bun run build:static

# The path list must include every GENERATED (gitignored) file the
# workarea serves — the test runners get a fresh checkout, so anything
# missing here 404s at runtime (e.g. TypeScript-iDevice bundles, ADR-2147-01).
- name: Upload dynamic bundles (chromium/firefox)
uses: actions/upload-artifact@v7
with:
Expand All @@ -65,6 +68,8 @@ jobs:
public/bundles/**
public/style/workarea/main.css
public/files/perm/idevices/base/slide/edition/slide-editor.bundle.js
public/files/perm/idevices/base/three-d-viewer/edition/three-d-viewer.js
public/files/perm/idevices/base/three-d-viewer/export/three-d-viewer.js

- name: Upload static distribution (static project)
uses: actions/upload-artifact@v7
Expand Down
11 changes: 9 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,10 @@ symfony.lock
.phpunit.cache
.idea/

runtime/
# Anchored to the repository root: an unanchored `runtime/` also matches source
# directories named `runtime` at any depth (e.g. a TypeScript iDevice's
# `src/runtime/`) and silently drops them from commits.
/runtime/
symfony_legacy
nestjs_legacy
test-results/
Expand Down Expand Up @@ -134,8 +137,12 @@ public/app/dist/
/app/dist/
/app/node_modules/

# Slide iDevice — pre-built editor bundle (regenerated by package.json postinstall)
# TypeScript iDevice bundles — generated from each iDevice's src/ by scripts/build-idevices.ts
/public/files/perm/idevices/base/slide/edition/slide-editor.bundle.js
/public/files/perm/idevices/base/three-d-viewer/edition/three-d-viewer.js
/public/files/perm/idevices/base/three-d-viewer/edition/three-d-viewer.js.map
/public/files/perm/idevices/base/three-d-viewer/export/three-d-viewer.js
/public/files/perm/idevices/base/three-d-viewer/export/three-d-viewer.js.map
.omc/

# Live-LMS harness working directories (see test/e2e/moodle/README.md)
Expand Down
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ These apply to every skill below. If you cannot meet them, stop and ask the user
| `src/**/*.ts` | Backend | `bun test` | `make fix` |
| `public/app/**/*.js` | Frontend | `vitest` | `make fix` |
| `public/files/perm/idevices/**` | iDevice | `vitest` | `make fix` |
| `public/files/perm/idevices/*/src/**` | iDevice (TypeScript, see [ADR-2147-01](doc/architecture/adr/ADR-2147-01-typescript-idevices-build-convention.md)) | `vitest` (`*.spec.ts`) | `make fix` |
| `src/shared/export/**` | Exporter | `bun test` | `make fix` |
| `src/db/migrations/**` | Database | `bun test` | `make fix` |
| `src/routes/api/v1/**` | API v1 | `bun test` | `make fix` |
Expand Down Expand Up @@ -91,6 +92,7 @@ make up # Docker dev environment
| `public/app/**/*.test.js` | Frontend unit tests | `vitest` |
| `public/libs/**/*.test.js` | Frontend lib tests | `vitest` |
| `public/files/perm/idevices/**/*.test.js` | iDevice tests | `vitest` |
| `public/files/perm/idevices/*/src/**/*.spec.ts` | TypeScript iDevice tests | `vitest` |
| `test/e2e/playwright/specs/*.spec.ts` | E2E tests | `playwright` |

### 5.2 Running Individual Tests
Expand Down Expand Up @@ -352,6 +354,7 @@ Domain-specific guidance lives in `.agents/skills/*/SKILL.md`.
| REST API v1 | [doc/development/rest-api.md](doc/development/rest-api.md) |
| Embedding in LMS | [doc/development/embedding.md](doc/development/embedding.md) |
| Profiling | [doc/development/profiling.md](doc/development/profiling.md) |
| TypeScript iDevices | [doc/development/idevices-typescript.md](doc/development/idevices-typescript.md) |
| Styles/Themes | [doc/development/styles.md](doc/development/styles.md) |
| Conventions | [doc/conventions.md](doc/conventions.md) |
| Architecture | [doc/architecture.md](doc/architecture.md) |
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,10 @@ test-frontend: check-bun check-env bundle ## Run frontend tests (with Vitest + h
bun test:frontend

.PHONY: test-unit-ci
test-unit-ci: check-bun check-tests check-env ## Run unit tests with lcov coverage for CI/Codecov
# Depends on `bundle` for the same reason test-unit/test-integration/test-frontend
# do: backend tests assert against generated assets (e.g. the TypeScript iDevice
# bundles), which are not committed.
test-unit-ci: check-bun check-tests check-env bundle ## Run unit tests with lcov coverage for CI/Codecov
@echo "Running unit tests with lcov coverage..."
@mkdir -p coverage/bun
$(TEST_ENV) bun test:unit:ci
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
id: ADR-2147-01
title: "TypeScript iDevices: src/ sources compiled by one convention-based build"
status: Proposed
date: 2026-07-30
tracking_issue: 2147
deciders:
- "@erseco"
reviewers:
- "@mnunezcedec"
- "@cristinavaldera"
related:
prs: [2147]
changes:
- "2153-three-d-viewer-interactions"
adrs: []
supersedes: []
superseded_by: []
ai_assistance:
tool: "Claude Code"
model: "claude-fable-5"
---

# ADR-2147-01: TypeScript iDevices: src/ sources compiled by one convention-based build

## Context

iDevices are classic-script objects loaded by the workarea and the exporters.
Historically each one is hand-written vanilla JavaScript committed directly
under `edition/` and `export/`. Two iDevices now keep their maintained source
in TypeScript instead — Slide (`src/` + a bespoke `scripts/build-slide-editor.ts`)
and Interactive Video (`src/` + a bespoke `scripts/build-interactive-video.ts`).
Two per-iDevice build scripts with duplicated Bun plumbing were already
diverging in flags and behaviour, and every future TypeScript iDevice would
have added another copy plus more package.json entries.

## Problem

How does the repository recognise, build, type-check and test an iDevice whose
maintained source is TypeScript, without a new build pipeline per iDevice?

## Decision drivers

- One obvious convention for the next TypeScript iDevice (zero new scripts).
- The shipped output must remain plain classic-script IIFEs; the language and
compile step are not a framework.
- Generated artifacts must never be committed; a clean checkout must
regenerate them through the existing pipeline (`build:all` / `make bundle`).
- Existing iDevices with special needs (Slide) must fit without renaming their
shipped bundles.

## Decision

**An iDevice that keeps a `src/` directory is a TypeScript iDevice**, built by
the centralized `scripts/build-idevices.ts`:

- **Convention:** `src/edition/index.ts` → `edition/<name>.js` and
`src/export/index.ts` → `export/<name>.js` — self-contained IIFEs
(`target: browser`, linked source maps, unminified), whose entry points
explicitly assign their window globals (`$exeDevice`, `$<name>`).
- **Escape hatch:** an optional `build.config.json` next to `config.xml`
replaces the convention for that iDevice (custom entries/naming/globalName/
minify/sourcemap, plus `externals` mapping bare imports to page-provided
globals so vendored libraries are never inlined). Slide uses it.
- **Type checking:** each TypeScript iDevice ships its own `tsconfig.json`
(strict for new code); the runner executes `tsc -p` for every one it finds.
- **Tests:** colocated `*.spec.ts` next to each module, run by **Vitest**
(`bun test` ignores `public/**`), plus bundle-contract smoke tests that
evaluate the compiled IIFEs.
- **Artifacts:** generated bundles and source maps are gitignored;
`build:all` runs `typecheck:idevices` + `bundle:idevices` before
`bundle:resources` (export bundles ship inside `idevices.zip`).

Package scripts: `typecheck:idevices`, `bundle:idevices`,
`bundle:idevices:watch`; the runner accepts `--only <names>` and `--watch`.

## Options considered

### Option 1: One bespoke build script per TypeScript iDevice (status quo)

Pros: each script is trivially readable. Cons: duplicated plumbing, per-iDevice
package.json entries, drift between scripts (they already differed in
sourcemaps, watch support and failure reporting).

### Option 2: Convention-based central runner + per-iDevice manifest (chosen)

Pros: the next TypeScript iDevice needs no build changes at all; one place to
fix bundler behaviour; deviations are declared, not programmed. Cons: one more
convention to know; the manifest is a small new format (documented in the
runner header and `doc/development/idevices-typescript.md`).

## Consequences

### Positive

- Adding a TypeScript iDevice = create `src/edition|export/index.ts` (+ a
strict `tsconfig.json`); building, type-checking and watching come for free.
- Slide and Interactive Video share one build path; Slide's output stayed
byte-identical apart from the generic externals shim's message strings.

### Negative

- A hidden convention: `src/` now has meaning. Mitigated by this ADR,
`doc/development/idevices-typescript.md` and the idevice skill.

### Neutral

- Classic-script iDevices are untouched; nothing forces a migration.

## Validation

- `scripts/build-idevices.spec.ts` covers discovery, the convention, the
manifest and its validation against the real repository state.
- `bun run build:all` exercises typecheck + build for every TypeScript
iDevice on every bundle/test target.

## References

- `scripts/build-idevices.ts` (runner; manifest schema in its header).
- `doc/development/idevices-typescript.md` (developer guide).
- PR [#2147](https://github.com/exelearning/exelearning/pull/2147).
Loading
Loading