Skip to content

[Bug]: Interactive scene iframe has no keep-alive — reloads on every remount (scene switch, mode toggle, re-parent) #619

@wyuc

Description

@wyuc

Summary

Interactive scene iframes reload (re-execute their HTML/scripts) whenever the playback chrome unmounts and remounts. The most visible trigger is toggling Pro mode (edit ↔ playback), but the root cause is structural and not specific to the editor: any path that tears down and rebuilds PlaybackChromeRoot re-mounts the iframe from scratch.

Steps to reproduce

  1. Open a classroom whose current scene is an interactive (iframe) scene.
  2. Toggle Pro mode on, then off (or trigger any flow that unmounts/remounts the playback chrome).
  3. Observe the interactive scene reload: the iframe re-parses its HTML and re-runs its scripts, losing any in-iframe state.

Root cause

Stage switches between EditChromeRoot and PlaybackChromeRoot via AnimatePresence as two mutually exclusive branches keyed by mode. Entering Pro mode unmounts the whole PlaybackChromeRoot subtree; exiting rebuilds it.

Stage (mode swap via AnimatePresence)
  └─ PlaybackChromeRoot      ← unmounted on edit, rebuilt on return
       └─ CanvasArea
            └─ SceneRenderer
                 └─ InteractiveRenderer  ← <iframe srcDoc> mounts fresh

InteractiveRenderer renders <iframe srcDoc={patchedHtml}> directly in the React tree (components/scene-renderers/interactive-renderer.tsx). There is no iframe reuse/persistence (e.g. portaling a single iframe into a stable host node), so a remount means a full reload.

This is pre-existing behavior of the playback chrome. The editor work merely adds a prominent new way to trigger it.

Impact

  • Interactive widget state is lost on every Pro mode toggle.
  • Visible reload flash; wasted work re-parsing/re-running iframe content.
  • Affects any future remount trigger, not just Pro mode.

Candidate fixes (need a direction decision)

  1. Persist the iframe: portal one iframe instance into a stable DOM host outside the mode-swap subtree, show/hide instead of unmount.
  2. Keep PlaybackChromeRoot mounted across mode swaps (hidden, not unmounted) so its iframe survives.
  3. Cache/restore iframe state at the widget messaging layer (widget-iframe store) — partial, only covers state the widget cooperates on.

Option 1 or 2 fixes it generally; both touch the playback chrome architecture, so this should land as its own change rather than riding along with the slide-editor PR.

Notes

Out of scope for the MAIC Editor slide-surface PR (#615) — filing separately so that PR stays focused.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions