# Interactive Course Editor

Integrated on 2 November and unified into the main frontend on 3 November 2026, using the pinned editor source documented in
[`presentation_editor/PROVENANCE.md`](../presentation_editor/PROVENANCE.md).

## Product naming and Arabic support

The visible editor name is **Interactive Course Editor** (محرر المقرر التفاعلي). Project creation, navigation, previews, publishing and downloads use **Interactive Course** terminology. Existing translation keys remain available, while their visible labels use the new wording. Routes, stored identifiers and native presentation documents retain their existing contracts. Exported course ZIPs still use the SCORM 1.2 standard internally; download filenames now use `interactive-course`.

Arabic text, RTL paragraphs, mixed Arabic/English text and Arabic workspace controls are supported. Font availability affects rendering: use the matching font family or upload the required font to the project's/personal/organization font library. This does not automatically translate presentation content or remove the PPTX import limitations below.

The Writing controls in the toolbar and text properties explicitly set automatic, RTL or LTR paragraph direction and convert selected text boxes between `٠١٢٣` and `0123`. The inline text toolbar converts the selected range (or the entire box when no range is selected) while retaining rich-text marks. Explicit paragraph directions are respected on the canvas and in PPTX export. Charts have an optional digit style; their underlying values remain numeric, and PPTX uses the [Eastern Arabic extended-LCID number format](https://help.libreoffice.org/latest/en-US/text/shared/01/05020301.html) `[$-02000401]0.##########`. Arabic learner counters, grades and H5P labels use Arabic-Indic display digits while input values, tracking IDs, answers and LMS data retain their existing contracts. Existing projects keep their stored text and chart formatting until the author changes them.

The terminology update passed the production build, 265 main-application tests, 155 presentation-editor tests and 48 backend tests (1,941 assertions). Focused localization lint passed. Checks include legacy translation-key compatibility, unchanged interpolated project titles, project creation through existing routes, and the existing Arabic/mixed-direction editor cases. No production deployment was performed.

## User flow

- The main frontend owns the PowerPoint editor as `app/workspaces/presentation`. It replaces the visible Course Structure tab and is the default authoring section. No iframe, separate editor build, or editor server is used.
- Uploaded PPTX files and blank projects open the presentation workspace before SCORM artwork is generated. Editing and saving use the presentation document and save an updated editable PPTX; the uploaded source remains an unchanged original backup.
- **Show slide** controls course inclusion and PowerPoint hidden-slide state. **Show in course menu** controls menu visibility separately. Hidden slides remain in the editable PPTX.
- **Save PowerPoint** persists a draft only. Autosave does the same. Neither opens an image-rendering job nor publishes slide images. Existing SCORM artwork, course settings and activities remain unchanged until explicit regeneration.
- **Regenerate SCORM images** first saves pending course edits and the presentation/PPTX, captures that saved revision, then renders and uploads the slides. Complete artwork is committed transactionally; interrupted/rejected generations retain the previous successful artwork. Keep this workspace open during the explicit rendering batch.
- Questions, groups, media, narration and H5P retain their course-slide IDs and tracking keys. Timers, transition overrides and flow ordering are preserved by slide identity, including across hide/restore and reorder. Duplicating a native slide copies its presentation content only; it does not clone attached activities.
- The old Course Structure component and Fix slide layout implementation remain in the source, hidden from the active workflow for potential future image editing.
- A saved draft blocks a new SCORM build until its images have been regenerated. The existing downloadable package is retained. Source-based regeneration remains blocked after native adoption.

## Import and export limits

Resizing through drag handles or the dimension inspector scales text (including imported mixed font sizes), shape labels, borders, shadows, corner radii, table contents, and chart typography. Side handles scale content by the changed dimension; corners use the smaller dimension ratio. Hold Shift to preserve proportions. Group and multi-selection resizing scale each object's contents, with one undo step when the drag ends; cancelling restores the original. Moving and rotating preserve content sizes. Shape and chart content scaling is optional in saved documents, so older documents retain their original appearance.

Text boxes fit the rendered font bounds when opened, edited, or resized. Short single-paragraph labels tighten to their text width while preserving alignment; wrapped and multiline text retain their wrapping width. Height includes Arabic ascenders, descenders, and diacritics, with a matching internal offset for fonts that extend above their CSS line box. Measurements use the renderer's markup and loaded fonts; editing and fitting share one undo step.

The browser imports supported PPTX objects into its editable document and generates a new PPTX when saving. It does not patch the uploaded ZIP in place and cannot guarantee all Microsoft PowerPoint features. SmartArt, source groups, embedded content and unsupported effects produce dismissible notices; they no longer turn the entire source slide into a background picture. Supported objects remain editable. Dismissal is retained in this browser, per project and slide. SVG pictures supplied through `asvg:svgBlip` are imported as image objects.

For existing courses, the editor includes the current course slides, including duplicates and extra image slides. Original and duplicated source slides are imported from the original PPTX using `source_slide_number`, independently of course order. Each copy receives independent object IDs while retaining its existing course-slide ID. Course-only image slides retain their artwork and clearly explain that their original text and shapes are unavailable. Removed course slides are not silently restored.

An artwork-only saved draft offers **Edit original PowerPoint**, which imports an editable working copy while retaining the saved theme and course identities. On the first successful replacement save, the prior artwork document is preserved at `native/recovery/artwork-{revision}.json`. This is an explicit action, not an automatic migration of existing drafts. Existing native drafts with editable additions are not classified as artwork-only.

If an uploaded project's original PPTX is missing, the editor shows **Original PowerPoint required**, explains that image slides cannot be edited as PowerPoint objects, and offers an original-file upload. It validates slide count and the saved source hash where available; it cannot prove identity from slide count alone when no original hash survives. An existing source is never overwritten. Intentional blank/native projects continue to open without an uploaded source.

SCORM output remains static slide artwork combined with the application's learning activities. Native object animations/links do not become learner interactions through rasterization. Representative real PowerPoint files still require acceptance testing.

## Storage and concurrency

- `native_presentations` stores revision metadata, source hash, stable native/course ID mapping, current document path and previous document path. JSON and artwork live under the existing private `conversions/{id}/native/` directory and count toward storage usage.
- Editable documents default to a 100 MiB limit, configurable with `PRESENTATION_MAX_DOCUMENT_MB=100` in the backend `.env` (positive whole MiB; applies to saves and restores). After changing it, run `php artisan config:cache` on deployments using cached configuration. Documents remain capped at 200 slides and 1,000 elements per slide. Image uploads are PNG up to 20 MB per slide. Native project font uploads allow 50 records and 20 MiB per upload; existing preparation fonts are also exposed to the editor.
- **My fonts** in the profile stores a private personal library. **Organization Settings → Fonts** lets organization admins upload shared fonts; members can use them and preview them from organization information. Each library allows 100 font families in TTF, OTF, WOFF or WOFF2 format. Editor uploads also enter My fonts. Family names must match the PowerPoint family name; missing fonts can instead be explicitly replaced in the existing font-resolution dialog.
- The editor lists its project fonts, the current user's personal fonts, and shared fonts for an active organization membership. External project collaborators do not receive the organization's entire library. Referenced library fonts are copied into private project storage on save, so subsequent library deletion or membership changes do not break saved project fonts. Font bytes remain authenticated; personal/organization scope is checked on each library request. Library and project copies count toward their respective storage usage.
- The native PUT route bypasses generic string trimming/null conversion so authored whitespace and empty text survive. Other API routes retain their existing middleware behavior.
- Identical document saves ignore `updatedAt` changes and retain the same revision. Failed revision/source checks keep the editor draft open and do not overwrite another save.
- Changed course controls are merged into the native document when reopened after successful image publication. Parallel course edits while unrendered native edits exist are rejected and the native document is retained for recovery. Do not overwrite the conflict with a forced save.
- Edited PPTX files are stored privately at `native/pptx/{revision}.pptx`; uploads validate the OOXML container and current revision. Download rejects a missing/stale PPTX. JSON and PPTX are saved sequentially, so a failed PPTX upload retains the editor draft and the successfully saved JSON for retry. Course-state snapshots preserve hidden-slide settings and flow ordering at `native/course-state/{course_revision}.json`. These files count toward quota.
- Native images are staged by generation/revision, checked for completeness and published transactionally. Published image files cannot be overwritten through the staging endpoint. Successful publication consumes one conversion entitlement.
- Current and one previous native JSON revision are retained. Image generations, including interrupted staging uploads, remain private and count toward quota; automatic native-generation garbage collection is not implemented in this batch. Project deletion continues to remove its conversion directory through the existing lifecycle.

## Preparation and deployment

From the frontend directory run `npm ci` and `npm run build`. The single frontend
build includes the presentation workspace and its bundled fonts. The optional
`presentation_editor` package is retained only for provenance and isolated engine tests;
its dependencies are not needed for application builds. No ASP.NET installation is required.

Apply the additive migration through the normal deployment gate, after database backup:

```powershell
cd documents_generator_tools_backend
C:/laragon/bin/php/php8.3/php.exe artisan migrate --path=database/migrations/2026_11_02_000001_create_native_presentations_table.php --force
C:/laragon/bin/php/php8.3/php.exe artisan migrate --path=database/migrations/2026_11_05_000001_create_workspace_fonts.php --force
C:/laragon/bin/php/php8.3/php.exe artisan route:clear
```

For Ubuntu use `php artisan ...` in the same backend-relative directory. Rebuild route/config caches and restart existing workers as required by the deployment guide. The migration was applied locally only to the verified Laragon MySQL connection `127.0.0.1 / documents_generator_tools`; no production deployment was performed.

`PRESENTATION_EDITOR_ENABLED=true` enables the opt-in editor. If the table is absent the editor availability endpoint returns false, so old project controls still load. Setting the flag false hides/disables native authoring but does not delete documents or bypass stale-image package checks. Projects already using native documents must retain native rendering support; disabling the feature is not a format rollback.

For local development, run the normal frontend `npm run dev` or root Windows launcher.
There is no prebuilt `public/presentation-editor` requirement. CSS and UI portals stay
inside the presentation workspace; project navigation saves its pending edits before
switching the active editor. Presentation keyboard listeners are removed on unmount.

## Earlier verification (2 November integration)

- Adapted editor: 130 unit tests passed (21 files); TypeScript/Vite build passed.
- Host frontend: production build and all 209 existing/adapted tests passed.
- Windows launcher: all 9 launcher tests passed.
- Focused backend: 54 tests / 482 assertions passed across native presentations, upload, quiz, media, layout and pipeline checks, including publication idempotency and immutable published artwork.
- Browser checks used a disposable SQLite database and isolated storage, not real project records. Verified blank-course creation, content editing, save/reopen, image generation, 390px properties drawer, actual PPTX upload, editing imported text into mixed Arabic/English, switching editor UI to Arabic and successful SCORM packaging from native artwork. The generated Arabic PNG was visually inspected.
- A final browser rerun after connecting editor/application language preferences also passed, with saved native revision 2 matching rendered revision 2 and a downloadable package.
- No production deployment, target Moodle LMS acceptance or exhaustive real-file fidelity testing was performed.

## Unified workspace verification (3 November)

- Main frontend: TypeScript/production build and all 209 tests passed.
- Presentation engine: all 130 tests passed from its new source location.
- Backend: 39 tests / 457 assertions passed across native presentation, course composition, quiz and media behavior. The native suite covers original-backup preservation, stale PPTX rejection, repeated saves, no-job draft saves, unchanged course artwork before regeneration, and preservation of attachments, timers, transitions and flow order after hide/restore/reorder.
- Windows launcher: all 9 tests passed without separate editor assets.
- Headless browser: uploaded a real generated PPTX; edited mixed Arabic/English text; downloaded and inspected updated OOXML; verified the original download byte-for-byte; verified no image requests before explicit regeneration; generated/published artwork; switched sections and between two projects; reopened saved content; checked 390px English/Arabic and the mobile properties drawer. Browser errors: none; document width matched the 390px viewport. Screenshots were visually inspected.
- Backend tests use SQLite in-memory databases. Browser acceptance uses the disposable `out/native-editor-qa` SQLite database and storage, not real project records. No production deployment or Moodle/LMS acceptance was run.
- Amiri and Geist font licenses are shipped under `public/licenses/presentation-fonts`.


## Editor feedback and loading UI

The workspace toolbar groups Save, Download and Regenerate actions, with course slide titles and visibility controls under **Design → Slide → Course settings** in the right-hand properties panel. The separate settings row has been removed, and the content-update badge sits next to **Regenerate SCORM slides** in the top action bar. A small draft badge replaces the persistent yellow reminders. Background-artwork compatibility is explained in a dismissible informational notice; errors use one alert with retry where applicable. Manual saves, downloads and publication show brief success notifications. Autosave uses the compact status indicator without repeatedly notifying the user.

Loading uses a consistent workspace skeleton for the module, document and fonts, with retry on recoverable load failures. Explicit regeneration shows saving/rendering/publication progress; shortcuts and paste editing are blocked during that operation. Notifications follow the workspace's light/dark theme and English/Arabic direction. Success notifications stay visible within the viewport on mobile.

The **SCORM slides need updating** badge compares slide content and appearance with a retained baseline, rather than comparing save revision numbers. Text, objects, geometry, backgrounds, theme colors/fonts, slide size and slide structure affect it; opening, unchanged saves, selection, speaker notes, course labels, menu/inclusion settings and editor-only properties do not. Undoing the content changes clears the badge. Successful regeneration establishes a new baseline; failed regeneration retains the previous baseline. Small revision-bound fingerprints under `native/content-state/` keep this status across reopening. Existing projects without fingerprints establish their initial baseline when first opened with this version. These fingerprints are UI status only: existing revision/conflict/publication/package guards remain authoritative.

The editing canvas reserves less margin, uses compact integrated toolbars, and opens with speaker notes collapsed. **Open full editor** is highlighted as the recommended mode, with an English/Arabic prompt explaining that it provides more space and clearer slide editing. It fills the browser viewport while retaining the tools; **Return to workspace** or Escape restores the page and scrolling. The recommendation appears in the existing header, without an additional popup or banner taking space from the canvas. **Fit slide width** provides a larger, vertically scrollable working view, while the existing fit control restores the complete slide. Both zoom labels now show the actual slide scale; the internal fit-relative slider/gesture multiplier is unchanged, so editing coordinates stay consistent. Top and bottom zoom controls share the same maximum.

Canvas acceptance used an isolated 85-slide copy at 1850×834: the fitted slide increased from 216px to 550px wide, expanded mode gave 753px, and fit-width gave 1278px. Browser checks passed for text editing, Undo, dragging, resizing, viewport expansion/exit, restored page scrolling, and the 390px properties drawer, with no uncaught page errors. The production build, 210 host tests and 135 editor tests passed for this update. These checks did not modify the real project.

Verification: frontend build and 209 host tests; 130 editor tests; browser inspection of light/dark loading, compatibility dismissal, save conflicts and retry (including Ctrl+S without duplicate toasts), downloads, regeneration progress and blocked keyboard edits, plus 390px English/Arabic layouts and visible translated success notifications. Browser checks used the disposable QA database/storage. No production deployment was performed for this UI update.

## Original-PPTX recovery and shared fonts (5 November)

- Original-file import now recovers all 143 images in the inspected 85-slide presentation, including 76 SVG-extension pictures previously omitted. Dry-run result: 484 text objects, 178 shapes, 21 tables, and editable content on all 85 slides. The original project draft was not automatically replaced.
- Existing course duplicates are included and receive independent object IDs. Extra image slides are included as image backgrounds with an explanatory notice. Old course order and stable slide IDs are used on adoption; new deletions/duplications act on the working document and take effect in the course only after regeneration.
- Missing-original recovery, retained artwork backups, activity mapping, private personal fonts, organization membership/admin boundaries, font storage accounting, and project font snapshots are covered by 16 backend feature tests (142 assertions).
- The presentation workspace has 133 passing tests, including SVG import, unsupported-feature notices, and independent duplicates. The host frontend production build and 210 tests pass, including organization-font admin/member UI.
- Headless browser checks in isolated SQLite/storage passed: artwork draft → editable original/duplicate slides plus extra image slide → save/reopen → regeneration; persistent warning dismissal; profile font upload/preview; organization shared-font upload; missing-original message and PPTX restoration; 390px English and Arabic RTL font layouts. No uncaught page errors were recorded.
- Local migration `2026_11_05_000001_create_workspace_fonts` was applied to the verified Laragon database. No production deployment or Moodle runtime acceptance was performed. Local QA artifacts are under ignored `out/native-editor-qa/`.

Known remaining optimization: saves still build and upload the complete JSON and PPTX. The 85-slide development-mode copy with recovered SVGs saved successfully but remains expensive; coalesced draft saves and deferred PPTX generation are future work. Missing fonts and unsupported PowerPoint features still require review before treating the browser output as visually identical to PowerPoint.

### Production save: “Failed to fetch”

**Confirmed incident, 2026-11-08:** the presentation PUT returned HTTP 500. Production logs reported `Allowed memory size of 134217728 bytes exhausted` in Laravel `Arr.php:195` and `NativePresentationController.php:245`. PHP was running with a 128 MiB request memory limit. The save path unnecessarily encoded the complete document twice and decoded the previous draft twice; generic validation also traversed all rich text, table cells and embedded image data for structural rules. The backend now reuses the encoded document and previously decoded draft, validates request metadata without copying document internals, and applies structural rules to a compact projection. The original complete document still passes the asset/link/depth checks and is saved unchanged. No schema migration is required for this optimization.

For the documented PHP 8.3-FPM deployment, set `memory_limit = 512M` in `/etc/php/8.3/fpm/php.ini`. Check the active pool's files under `/etc/php/8.3/fpm/pool.d/` for a `php_admin_value[memory_limit]` override; update an active 128M override to 512M as well. Validate and reload the service:

```bash
sudo php-fpm8.3 -t
sudo systemctl reload php8.3-fpm
```

Use the PHP version/socket configured by the API virtual host if it differs from this guide. Changing only CLI PHP or rebuilding the frontend cannot change FPM's request memory limit. Pool admin values override PHP configuration ([PHP-FPM configuration](https://www.php.net/manual/en/install.fpm.configuration.php)). Retry Save in the existing editor and verify a successful PUT followed by the PPTX POST. Keep the existing editor tab open while resolving the failure. Apply the reviewed backend optimization through the normal deployment process as well; the 512 MiB setting provides headroom but does not replace the code fix. Size FPM concurrency for available server RAM rather than removing the memory limit.

Local validation: 21 native presentation/validator tests passed (195 assertions), including save/reopen, restore, revision conflicts, unchanged complete documents, malformed geometry, duplicate slide IDs, and asset/link checks inside rich content excluded from the structural copy. A separate PHP 8.3 subprocess validated a synthetic 40-slide, 5.38 MiB rich-text document at a 128 MiB limit: the previous code exhausted memory, while the updated code completed with 104 MiB peak allocated memory. This is a standalone validation benchmark, not an authenticated production save or a guarantee that every request fits 128 MiB. Production retry after the FPM/configuration and backend updates remains required.

Saving has three stages: prepare the PowerPoint (including image reads), PUT the editable JSON to `/api/v1/powerpoint-to-scorm/conversions/{id}/presentation`, then POST the generated file to the same path plus `/pptx`. The first write can also request `/sanctum/csrf-cookie`. A failure before the PUT does not send a draft; an acknowledged PUT followed by a failed upload has already saved the editable draft. Keep the editor open until saving succeeds. A lost response leaves the result uncertain; do not assume the server never received the request.

The frontend now identifies the failed stage, includes the failed API method and URL without query-string tokens, and explicitly reports an acknowledged draft revision when its PPTX upload fails. It retains that revision for a subsequent save. HTML responses with HTTP 413 or 502/503/504 have specific messages; server JSON validation/conflict errors retain their original details. An unreachable external image is identified without including its signed query string or embedded image data. Deploy the rebuilt main frontend `dist` to receive these diagnostics; no schema migration is needed.

To diagnose an affected save, use browser DevTools → Network with **Preserve log** enabled. Click Save once and record the failed request URL, method, status, request size, timing, and Console error. Do not share cookies, authorization headers or signed URL tokens. Check the API Apache error/access logs and Laravel log at the same timestamp. A normal health check or OPTIONS response is insufficient to verify the authenticated PUT and PPTX upload.

- If the request is an external image read, restore the image or its permitted origin; changing PHP upload settings will not repair that image.
- For HTTP 413, inspect the active HTTPS API virtual host's `LimitRequestBody` and PHP-FPM's `post_max_size` / `upload_max_filesize`, including any proxy in front of Apache. The application accepts editable JSON up to `PRESENTATION_MAX_DOCUMENT_MB` (100 MiB by default) and a native PPTX file up to 100 MiB; request metadata and multipart uploads need additional overhead. Keep request-body limits above the configured document limit and allow sufficient PHP/browser memory for parsing and rendering large documents. See [production deployment](ubuntu-apache-deployment.md), sections 5 and 9. Inspect FPM configuration rather than CLI `php -i` alone.
- For 502/503/504 or a reset connection, inspect Apache/PHP-FPM logs, worker health, memory and request timeouts before changing limits.
- For a browser CORS error, check the actual failing response, not only preflight. Credentialed requests require the exact frontend origin and credentials support. Keep the existing session/CSRF protection.
- For 401/419, check session cookies and CSRF setup. For 409, review the revision conflict before reopening; do not overwrite another editor's draft.

Read-only checks on 2026-11-08 confirmed that `https://tools.abdalrhman.dev` serves a build using `https://toolsapi.abdalrhman.dev/api/v1`, the API health endpoint returns 200, and the presentation PUT preflight and unauthenticated GET return credential-enabled CORS headers for the frontend origin. These checks did **not** reproduce an authenticated production save or establish its failure cause. Fetch rejects on network/browser failures rather than ordinary HTTP error statuses: [MDN fetch documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch).

## Combined course/editor header

On the PowerPoint tab and initial presentation preparation screen, the course identity and actions share one header with native Save, Download, full editor mode, and Regenerate controls. Secondary course actions use compact icons with tooltips and accessible names; Build SCORM keeps its label. Other authoring sections retain the existing course header. Loading and recovery states keep course actions available. Full editor mode includes the same combined header; course actions that open page-level navigation or preview leave full editor mode first so their dialogs remain visible.

Verified the production build, 210 host tests, 135 presentation tests, and browser save/download, course preview from full editor mode, tab switching, and Arabic RTL mobile layout in isolated QA storage.

## Discard ungenerated edits

The combined editor bar includes **Discard all changes** with a confirmation dialog and Cancel. Confirming restores the editable document used for the last successful SCORM slide generation, including slide order, content, notes, course titles and visibility. Autosaved draft changes are included. Current course slides, activities, stable slide mappings and player settings are untouched; this action does not regenerate slides. Before the first native generation it reimports a working copy of the original PPTX, or restores the initial blank presentation for a native project. The original upload remains unchanged.

Generated editable JSON checkpoints are retained under `native/restore/published-{revision}.json`. Before restoring, the currently saved draft is backed up under `native/discarded/`. Restoration creates a new, increasing revision, clears local undo/redo history, and resets the content-update indicator. Autosave pauses and existing saves finish first so a late autosave cannot overwrite the restore. Course/source/revision conflicts leave the draft intact and display an error in the dialog. Older projects without a recoverable editable checkpoint have the action disabled with an explanation; their generated pictures are never silently treated as an editable restore copy.

Acceptance covers original-copy restoration before generation; restoration after multiple autosaves and old document cleanup; preserved course records and activities; saved draft backup; stale/foreign requests and missing checkpoints; a blank project before its first autosave; and autosave queue draining. Isolated browser checks cover Cancel, failed restore, restoration during an in-flight autosave, persistence after reload, full editor mode and Arabic mobile confirmation. QA uses disposable SQLite/storage, never the live project.

Validation: production build, 210 host tests, 136 presentation tests, and 17 native backend feature tests (178 assertions) passed. Browser flows passed with no uncaught page errors; Arabic mobile confirmation was visually inspected after its opening animation completed.

## PowerPoint table fidelity

The Arabic training-program table in the original 85-slide deck exposed an importer bug: OOXML `hMerge`/`vMerge` continuation cells were retained alongside spanning anchors. Browser tables then created extra columns, shifted text and exceeded the table bounds. Imports now omit continuation cells and retain anchor spans, cell margins, vertical alignment, vertical text rotation and proportional paragraph line spacing. PPTX export preserves these fields. Text editing retains imported paragraph spacing.

Saved drafts from the old importer receive a read compatibility fix in the renderer, table data editor and PPTX exporter: empty cells occupying covered grid positions are omitted; nonempty cells are preserved. Rendering/export do not rewrite the stored draft. This cannot recover rotation or margins that an old draft never stored; those formatting details require importing or repairing from the original file. No automatic original-deck replacement or SCORM regeneration occurs.

Browser validation used the actual original deck in an isolated renderer, without modifying a project or database. Its second-slide table has nine columns, two vertically rotated merged labels and cell counts `[9,9,7,7,7]`. Import/export/reimport preserved those counts and rotations, the table fitted its intended bounds, and Arabic cell editing succeeded with no uncaught page errors. Screenshots and results are in ignored `out/native-editor-qa/table-*`.

## Table resize and text fitting

Table resize gestures and numeric width/height changes scale row heights, column widths, text sizes, cell margins and borders together. Text uses the smaller of the width/height ratios to avoid stretching glyphs. Gesture previews and the committed document use the same transformation; one drag creates one undo entry. Moving or rotating a table does not scale its content. The toolbar font-size input and the right Style panel both support tables, preserving relative header/body sizes. Font sizes and scaled dimensions persist in editable JSON and PPTX export.

Cell contents now sit inside fixed table geometry instead of forcing browser rows beyond the selection frame. A measured, proportional fit shrinks overflowing text and reflows words inside the available cell area, including rotated merged labels and old saved drafts. It does not crop text or change the original upload. This additional display fitting also applies to SCORM slide capture; it does not rewrite stored font sizes. For editable PowerPoint output, choose the intended font size using the font controls rather than relying only on display fitting.

Verification on the actual training-program table: browser handle resize reduced visible width from 523px to 388px with matching content/frame dimensions; font size scaled from 36 to 26.35; Undo/Redo worked; toolbar and sidebar font controls worked; export/reimport retained an explicitly selected 18px font; oversized text stayed inside every cell; SCORM PNG capture succeeded. Screenshots and results are under ignored `out/native-editor-qa/resize-*`. No project records or course activities were modified.

## Imported table row-height recovery

Some PowerPoint imports and older native drafts contain zero or negative table row heights. Strict document validation previously rejected the entire presentation with `rows[n].height` / `Too small: expected number to be >0`. New imports and read compatibility now reconstruct positive row sizes from the table's existing frame. Known positive row heights are retained when the frame has remaining space; otherwise the rows are proportionally fitted within that frame. Table/cell identities, content, merge spans, styling and the original uploaded PPTX are preserved. The saved source object is not mutated during opening, and unrelated invalid data still fails strict validation.

This recovery ships in the main frontend build. Deploy the updated frontend, publish its rebuilt `dist`, and reopen the affected existing project; no database migration, database reset, source-file replacement or manual row deletion is required. The uploaded original stays unchanged; repaired draft data is persisted through the normal editor save workflow.

## Imported text-box font-size controls

Imported PowerPoint runs carry explicit font sizes in rich-text marks. Previously the toolbar and sidebar changed only the text element's fallback size, leaving those marks to override it. Whole-text-box font-size changes now remove only the run-size overrides, allowing all runs to inherit the chosen size while retaining their font families, colours, bold/italic marks, text and paragraph direction/spacing. Toolbar multi-selection and direct element updates use the same formatting helper; locked text is unchanged. Undo restores the original mixed run formatting.

Verified against the actual first-slide Arabic title: eight rendered spans changed from 96px to 18px via the toolbar and to 12px via the sidebar. Undo/Redo and JSON reopening preserved the intended result; export/reimport returned 12px. Browser checks recorded no uncaught errors. Production build, 210 host tests and 144 presentation tests passed. QA screenshots/results are under ignored `out/native-editor-qa/font-size-*`; no project records were modified.
