# H5P production editor integration

Implemented locally, 13 October 2026. H5P is feature flagged and defaults to disabled. No production deployment, database reset, or Moodle import was performed.

## Setup and migration order

Use the existing application's supported PHP/Node versions and normal environment, authentication, queue and private-storage configuration. Commands below run from the indicated folders. On this Windows installation PHP is `C:/laragon/bin/php/php8.3/php.exe`; use that executable in place of `php` if it is not on PATH.

1. Back up the target database and private conversion storage. Inspect the active connection and `php artisan migrate:status` before applying anything. Locally the inspected connection was MySQL `documents_generator_tools`, with existing H5P records; those records were retained.
2. Backend: `composer install`. Apply existing outstanding application migrations in their normal chronological order, then `php artisan migrate --path=database/migrations/2026_10_13_100000_add_h5p_studio_authoring.php`. The new migration creates missing H5P tables or adds fields to existing H5P tables. It does not reset data. Do not run `migrate:fresh`.
3. Frontend: `npm ci`, `npm run sync:h5p-runtime`, `npm run sync:h5p-libraries`. The library command uses the vendored eight official bundles and verifies their pinned SHA-256 hashes. No moving upstream download is needed for normal setup.
4. Backend: `php artisan h5p:setup`, then `php artisan h5p:check`. Setup validates bundles against `resources/h5p-catalog.lock.json` before installing the exact 33 library/dependency versions. The runtime is pinned to `h5p-standalone` 3.8.2. Preserve bundled licenses and notices. The check verifies runtime and library inventories, including 1,049 library files.
5. Configure malware scanning for production: `H5P_SCANNER_ENABLED=true`, `H5P_SCANNER_REQUIRED=true`, and the available `H5P_CLAMDSCAN_BINARY`. Scanner failures are failures, not a successful readiness signal. Local fixtures used the local environment's optional scanner configuration.
6. Keep `H5P_ENABLED=false` until the target environment passes readiness and the acceptance walkthrough below. Enable explicitly for the reviewed environment, refresh configuration/route caches using the application's deployment procedure, and restart long-lived queue workers. Build the frontend with `npm run build`.

For local development run the existing backend server/worker and frontend `npm run dev`; this is the production editor at port 5173, not the independent prototype on 4176. The local review used Laravel at port 8000. Use a hidden-window launcher if needed; H5P adds no new command-window launcher.

`--refresh-lock` on the frontend library synchronizer is an explicit dependency upgrade operation: review the changed archives, semantics, adapters, dependency inventory and licenses and regenerate the canonical catalog before release. Authors have no API for installing executable libraries.

## Authoring, persistence and access

The H5P tab beside Media has eight focused content forms, selected-slide activities and Content / Placement & appearance / Learner behavior settings. Activities support duplication, slide reassignment, soft removal/restoration, independent button/inline rectangles, dialog/side-panel presentation, percentage positioning, alignment, snapping, layers and keyboard alternatives. Coordinates remain physical left/top in RTL.

Drafts join the existing nested save coordinator, 800 ms autosave, Save now, project-tab guards and package-build save transaction. The server checks document revisions under the conversion write lock. A stale save returns 409 and retains the local draft; it does not overwrite the newer revision. Incomplete authoring can be saved, but preview/export requires valid content. Unsafe/invalid fields and foreign asset references are rejected atomically. H5P mutations mark the existing package outdated.

Assets are private project raster uploads (PNG/JPEG/WebP), with size/dimension, ownership, quota and hash checks. Immutable portable content contains copied image assets. Authenticated and code-authorized shared previews receive expiring signed item-specific asset grants; preview files are hash checked and reject traversal. H5P activity instances run in separate frames with source, nonce, identity and content-revision validation, and listeners are disposed on navigation/tab changes.

Slide removal preserves attachments. Restoring the stable slide identity restores its attachments. The existing slide-duplication `copy_media` option includes H5P; copies receive new tracking identities. Existing imported H5P records from the older branch remain retained and read-only in custom forms, with remove/restore supported. They require review/re-authoring before this portable export path; unsupported legacy content is never silently omitted.

## Playback and SCORM

The eight adapters generate native content for pinned real H5P libraries. Editor activity previews, whole-course/shared previews and exported courses use one playback/completion bridge. Submission completes assessed tasks regardless of correctness. Cards require every back, accordion every section, and hotspots every point. Loading alone never completes an activity. Authored feedback remains visible.

Required H5P tasks block forward navigation and course completion, in addition to existing timer/media/native-question rules. H5P contributes no course grade points. Completion and compact attempt summaries use stable tracking identities and content revisions. Content edits invalidate only the affected completion; placement/title/appearance changes preserve completion. Unfinished detailed answers may restart.

H5P packages use configuration version 7 and an `h1|` compact suspend-data wrapper around the existing v4 state. Readers accept legacy formats; courses without H5P retain their existing configuration/state behavior. Packaging checks the combined worst-case 4,096-character SCORM 1.2 suspend-data budget and reports excess. It verifies all required content/assets/dependencies before building. Package generation uses a saved revision and the existing temporary-file swap, preserving the last valid ZIP on failure.

The ZIP contains the runtime, dependencies, native content JSON, localization, theme, completion bridge and local assets. All packaged assets appear in `imsmanifest.xml`. Learner playback needs an ordinary SCORM 1.2 LMS API, without DocuDeck servers or a Moodle H5P plugin.

Excluded: `.h5p` import UI, generic H5P editor, author-installed libraries, weighted grading and detailed unfinished-answer resume. Native adapter patterns follow the [H5P author tutorials](https://h5p.org/documentation/for-authors/tutorials) and [package specification](https://h5p.org/documentation/developers/h5p-specification).

## Diagnostics and rollback

Run `php artisan h5p:check` after setup and before enabling a deployment. Missing/unapproved/hash-mismatched runtime or libraries are blocking errors. Preview/export validation reports the affected activity. Revision conflict recovery uses the existing reload/discard workflow; preserve edits until the author chooses recovery.

If an imported SCORM activity reports `Unexpected token '<'` while parsing JSON, inspect the response to its `h5p.json`, `content/content.json` and library JSON requests. A login page indicates that the LMS session was not sent. The shared bridge uses `credentials: "same-origin"` so protected files on the LMS receive the learner's session cookie. Rebuild and download the SCORM ZIP after updating the bridge, then replace the LMS package; an existing ZIP retains its embedded runtime. Missing files or other HTML error responses require checking the failing URL separately.

To roll back availability set `H5P_ENABLED=false`, refresh cached configuration and restart workers. The H5P tab becomes unavailable and projects with active H5P cannot produce a replacement package. Existing standalone ZIPs continue to work. Keep the additive schema, private activities/assets and installed libraries; the migration's down method deliberately does not delete authored data. No database rollback/reset is needed to disable the feature.

## Acceptance evidence and remaining checks

Full backend suite: 113 tests, 1,889 assertions passed. Full frontend suite: 143 tests passed; TypeScript/Vite build and ESLint passed. Subsequent focused H5P tests cover the final Arabic-default correction. Backend coverage includes all eight real adapters, portable manifests, permissions/private grants, upload ownership, draft recovery, revisions, atomic failures, slide lifecycle/copy options, completion invalidation, missing libraries and budget failures. Frontend coverage includes all eight forms, bounds/placement, event ownership/disposal, resume/legacy state and dirty-save/conflict guards.

Browser review used real libraries over local HTTP with external connections blocked by the review server's CSP. All eight activities were interacted with, including wrong assessed answers, keyboard drag/drop, every card back, accordion section and hotspot. Completion gates, resume, content-revision invalidation, dialogs, side panel and inline playback were reviewed. English/Arabic desktop and mobile views, long labels, RTL physical keyboard movement/resizing, independent cached rectangles and mobile focus/Escape were checked. Upstream Arabic runtime defaults are supplemented without translating authored text.

Actual browser 200% zoom and physical touch-device QA remain manual acceptance checks; viewport testing does not claim to replace them. No target Moodle environment was supplied: Moodle ZIP import, LMS-specific resume and completion are **not tested**. Keep the feature flag for staged rollout until those target checks are signed off. No production deployment was performed.

Sample package, screenshots and a repeatable offline API harness are in [h5p_acceptance](h5p_acceptance/README.md).

## Activity appearance update, 14 October 2026

Placement & appearance now includes a per-activity palette for activity/content backgrounds, text, borders, options (normal, hover and selected), action buttons, correct/incorrect feedback and focus outlines. Palette colors are validated hex values, autosaved with the studio document, and included in authenticated/shared previews and each activity’s portable SCORM stylesheet. Appearance changes preserve content revisions and completion. Updated signed preview URLs prevent reuse of a cached palette after an appearance edit. Existing authored activities use the default palette until customized; no schema change is required.

Inline presentation hides launch-button label/color/shape/icon and popup destination/size controls. Returning to Action button retains these settings. Dialog size is shown only for Dialog, while placement, layering, completion and activity colors remain available for Inline.

The appearance editor now displays the actual selected activity while keeping palette controls editable. Color-picker input events send the full draft palette through the activity’s existing parent/nonce boundary and update CSS variables without a server round-trip or activity reload. Hover/selection/feedback can be exercised without changing course progress. Show slide placement returns to the slide canvas; changing a palette color returns to live appearance. Color-only autosaves leave in-flight content grants valid and version the stylesheet URL for newly opened previews.


Activity settings are grouped into display, position/size, button design, activity window and border sections. Advanced activity colors expand into background/text, answer options, activity buttons and feedback/focus groups. The selected activity, autosave status and settings navigation stay visible while scrolling. Moving, duplicating and removing an activity are under Manage activity. Placement edits return to the slide view; palette edits update the live activity preview. The mobile settings drawer has a backdrop, background scroll lock, keyboard focus wrapping and Escape-to-close behavior. Local checks cover English/Arabic layouts, drawer keyboard use, and no horizontal overflow at 390, 1024, 1280 and 1500 pixels.


## Overall H5P design, 15 October 2026

Apply the additive migration `php artisan migrate --path=database/migrations/2026_10_15_100000_add_h5p_overall_settings.php` before deploying the updated editor. Restart long-lived queue workers after updating PHP services. The migration adds nullable JSON settings to the H5P document; activity content and tracking identities are preserved.

Open H5P → Overall settings to edit the project’s shared colors, opacity, button shape/icon and activity-window settings. New authored activities use this design by default. For an individual activity, open Placement → Design settings and choose **Use overall H5P settings**. With this option on, the activity follows future project-wide design changes; the Edit overall settings shortcut opens the shared controls. Turn it off to start a custom design from the currently visible design and edit that activity’s colors, opacity, border, shape/icon and activity window. Inline activities expose the relevant content and border controls. Custom designs remain unchanged when overall settings change. Turning the option back on adopts the current shared design. Content, slide assignment, placement and completion remain individual. The sidebar identifies Overall design and Custom design, while Overall settings shows their counts. Design edits share the document revision/autosave/conflict checks and mark the package outdated.

The same design resolver feeds private/shared H5P stylesheets, editor/learner previews and portable SCORM export. An existing exported ZIP cannot change when an author changes settings: rebuild and replace the package in the LMS. Local validation passed 10 H5P backend tests (927 assertions), 40 focused frontend/editor/runtime tests, the TypeScript/Vite build and lint on changed H5P modules. The current project’s exported rounded button was browser-checked at a computed 14px border radius; target Moodle import remains unverified.


The overall H5P design UI uses Activities / Overall settings tabs and a persistent preview beside grouped controls. The preview switches between on-slide button styling and the real activity’s live color preview. Its selector always lists all eight supported activity types as working samples, alongside existing project activities. Samples use signed, expiring preview URLs and the installed H5P libraries; they do not create activities, assets or tracking records and are never exported. The preview demonstrates the shared design without changing an existing activity’s inheritance choice. Rebuild an existing package after changing shared or custom designs to update learner playback in the LMS.

As of 18 October 2026, per-activity inheritance is stored in the existing `studio.use_overall_settings` JSON field; this change requires no new migration. Missing flags on authored records default to overall settings, and explicit `false` selects the activity’s own design. Backend saving, stylesheet resolution and SCORM collection honor that choice. Retained imported/legacy activities continue their existing review workflow. Publish frontend and backend together so an older editor cannot overwrite inheritance choices. The original migration above is still required on installations without document settings. No application database migration or `.env` edit was performed for the inheritance change.

Inheritance validation: 11 H5P backend tests passed (1,043 assertions), and the full guarded in-memory SQLite backend suite completed with 168 tests / 2,492 assertions, no failures and one renderer-dependent skip. All 175 frontend tests, TypeScript/Vite build and lint passed. Coverage includes custom design preservation, rejoining the shared design, new-activity defaults, independent activities on other slides, revision conflicts, unchanged content/tracking identities, rejected invalid colors, and matching preview/export styles. The linked control was also inspected in the live editor without changing course data. These are local checks, not a new Moodle-import acceptance.

To relink the entire project, use **H5P → Overall settings → Use one design everywhere → Apply overall settings to all activities**. Confirmation explains that custom designs are replaced by the current shared design. This includes editable activities on other slides and removed activities, preserving content, position, completion, removal state and tracking identities; retained imports stay unchanged. The action uses existing revision-checked autosave, waits for an in-flight save when necessary and retains the draft if saving fails. With no custom designs remaining, the action is disabled. No additional backend API or schema is required. Bulk-action validation passed 177 frontend tests, including cancellation, cross-slide and removed records, legacy exclusions and failed-save/package blocking checks.
