<div class="doc-intro">
  <h1>PaperScape Technical Overview</h1>
  <p class="subtitle">Interactive visual canvas for Giraffe components inside OpenForum. This guide explains the runtime, bundled tools, and current maintenance backlog.</p>
</div>

<nav class="doc-table">
  <table>
    <thead>
      <tr>
        <th colspan="2">Contents</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>
          <ul>
            <li><a href="#overview">1. Overview</a></li>
            <li><a href="#runtime">2. Runtime Features</a></li>
            <li><a href="#architecture">3. Architecture Highlights</a></li>
            <li><a href="#bundled-apps">4. Bundled Apps &amp; Assets</a></li>
          </ul>
        </td>
        <td>
          <ul>
            <li><a href="#developer-tools">5. Developer Utilities</a></li>
            <li><a href="#persistence">6. State Persistence</a></li>
            <li><a href="#extending">7. Extending PaperScape</a></li>
            <li><a href="#issues">8. Known Issues &amp; Risks</a></li>
            <li><a href="#command-bus">9. Command Bus API</a></li>
            <li><a href="#next-steps">10. Next Steps</a></li>
          </ul>
        </td>
      </tr>
    </tbody>
  </table>
</nav>

<section id="overview">
  <h2 class="doc-section-title">1. Overview</h2>
  <p>PaperScape runs under <code>/OpenForum/AddOn/PaperScape</code> and embeds a layered, animated canvas built on the <strong>Giraffe</strong> rendering toolkit. Authors can drag in scripted components, compose scenes, and interact with supporting tools without leaving the browser.</p>
  <p>The controller initialises a full-screen canvas, touch/pen support, and an off-canvas side menu that surfaces actions and registered items. Modal editing forms reuse OpenForum binding to configure each object at runtime.</p>
</section>

<section id="runtime">
  <h2 class="doc-section-title">2. Runtime Features</h2>
  <ul>
    <li><strong>Drop ingestion:</strong> Handles <code>.giraffe.js</code>, <code>.giraffe.json</code>, and common images (JPG/PNG/SVG/WEBP), converting them into live canvas items.</li>
    <li><strong>Item registry:</strong> Every added object is registered and listed in the "Items" menu for quick re-selection of edit dialogs.</li>
    <li><strong>Panning &amp; zoom:</strong> Background composites implement click-drag panning plus wheel-based zoom, keeping large diagrams manageable.</li>
    <li><strong>Scene persistence:</strong> Save/Load actions serialise the active scene to <code>paperScape.json</code> alongside the addon and restore on reload.</li>
    <li><strong>Modal editing:</strong> When available, <code>getForm()</code> markup renders inside <code>#editForm</code>; otherwise a default remove-only fragment is shown.</li>
  </ul>
</section>

<section id="architecture">
  <h2 class="doc-section-title">3. Architecture Highlights</h2>
  <ul>
    <li><code>page.js</code> bootstraps <code>PaperScape</code>, sets up the off-canvas menu, and binds Save/Load/Full Screen actions.</li>
    <li><code>paperscape.js</code> (v0.0.5) orchestrates canvas layers, interaction state, drag-and-drop processing, select-box toggles, and item registration.</li>
    <li>Dependencies include <code>/OpenForum/Giraffe/giraffe.js</code>, Foundation's off-canvas shell, and OpenForum helpers such as <code>OpenForum.loadJSON</code>, <code>saveJSON</code>, and <code>IntraQ</code>.</li>
    <li>Extension hooks: <code>postRegisterItem</code>/<code>postRemoveItem</code>, <code>addFileProcessor</code>, selectors for view/control/overlay layers, and <code>setAllowDrag</code> / select-box controls.</li>
    <li>Drop handlers use a processor table so new file types can be registered dynamically.</li>
  </ul>
</section>

<section id="bundled-apps">
  <h2 class="doc-section-title">4. Bundled Apps &amp; Assets</h2>
  <ul>
    <li><strong>Measure tool:</strong> <code>Apps/measure.giraffe.js</code> plus <code>measure-recalibrate.html.fragment</code> to calibrate distances and units.</li>
    <li><strong>Whiteboard:</strong> <code>Apps/white-board.giraffe.js</code> adds a simple drawing surface with selectable pens.</li>
    <li><strong>IntraQ connector:</strong> <code>Apps/intraq-connector.giraffe.js</code> bridges to the developer console using the "PaperScape" queue.</li>
    <li><strong>Giraffe editor launcher:</strong> <code>Apps/giraffe-editor.giraffe.js</code> opens the standalone Giraffe editor preview.</li>
    <li><strong>Seed JSON:</strong> <code>seed.giraffe.json</code> and <code>dropable.giraffe.json</code> demonstrate serialised composites for import testing.</li>
  </ul>
</section>

<section id="developer-tools">
  <h2 class="doc-section-title">5. Developer Utilities</h2>
  <ul>
    <li><code>/OpenForum/AddOn/PaperScape/Developer</code> provides dual StandaloneEditor panes for JavaScript and JSON, streaming results through <code>OpenForum.IntraQ</code>.</li>
    <li><code>Developer/test.js</code> shows runtime scripting against live canvas items (e.g., updating the IntraQ connector message).</li>
    <li><code>Developer/vis-prog-intraq.js</code> illustrates integrating an external "Visual Programming" component via queue messages.</li>
    <li><strong>Modal Dialog API:</strong> invoke <code>paperScape.dialog.show(options)</code> to pop a reusable overlay with PaperScape-styled controls.</li>
  </ul>
  <pre class="doc-code"><code>paperScape.dialog.show({
  title: "Storage Manager",
  message: "Load or save your scene.",
  fields: [
    { name: "path", label: "Server Path", value: "/HomeLab/Scene.json" },
    { name: "autosave", label: "Autosave Key", value: "PaperScape/autosave" }
  ],
  actions: [
    { label: "Load", style: "primary", onClick(ctx) { loadState(ctx.getValue('path')); ctx.close(); } },
    { label: "Save", style: "secondary", onClick(ctx) { saveState(ctx.getValue('path')); } }
  ]
});</code></pre>
</section>

<section id="persistence">
  <h2 class="doc-section-title">6. State Persistence</h2>
  <ul>
    <li><code>PaperScape.toJson()</code> captures each registered item with its serialised state and original source payload for replay.</li>
    <li>Image drops store data URLs inside <code>paperScape.json</code>; large images inflate the save file and should be used sparingly.</li>
    <li>Scenes are currently versionless—saving overwrites <code>paperScape.json</code> with no rotation or snapshots.</li>
  </ul>
</section>

<section id="extending">
  <h2 class="doc-section-title">7. Extending PaperScape</h2>
  <ol>
    <li>Create a <code>.giraffe.js</code> module exporting <code>target = YourConstructor;</code> and implement <code>getName()</code>, <code>getContainer()</code>, plus optional <code>toJson()</code>, <code>fromJson()</code>, and <code>getForm()</code>.</li>
    <li>Drop the script onto the canvas or call <code>paperScape.load(\"/path/to/script.giraffe.js\")</code> to instantiate it at the pointer location.</li>
    <li>Provide modal edit markup (e.g., <code>default.html.fragment</code>) so <code>openInterface()</code> can render a configuration form.</li>
    <li>Use <code>paperScape.addFileProcessor()</code> to support new file types without modifying the core loader table.</li>
  </ol>
</section>

<section id="issues">
  <h2 class="doc-section-title">8. Known Issues &amp; Risks</h2>
  <ul>
    <li><strong>Shadow presets:</strong> The low-shadow instance overwrites the exported high-shadow reference (<code>paperscape.js</code>:391-396).</li>
    <li><strong>Duplicate load:</strong> <code>fromJson()</code> appends without clearing existing items, so repeated loads duplicate content (<code>paperscape.js</code>:27).</li>
    <li><strong>Security:</strong> Dropped <code>.giraffe.js</code> files execute via <code>OpenForum.evaluate</code>; only trusted sources should be used (<code>paperscape.js</code>:145).</li>
  </ul>
</section>

<section id="command-bus">
  <h2 class="doc-section-title">9. Command Bus API</h2>
  <p><code>/OpenForum/AddOn/PaperScape/commandBus.js</code> publishes the shared command bus so every embedded app, service worker, or MCP agent can participate in delete / undo / redo flows without touching PaperScape internals.</p>
  <ul>
    <li><code>registerCommandParticipant()</code> wires handlers into a shared dispatcher and exposes per-participant <code>pushHistoryEntry()</code>.</li>
    <li><code>pushHistoryEntry()</code> populates the shared stack, emits telemetry, and broadcasts queue packets unless <code>broadcast:false</code>.</li>
    <li><code>onHistoryEvent()</code> reports <code>push</code>/<code>undo</code>/<code>redo</code>/<code>clear</code>/<code>telemetry</code>/<code>error</code> events for dashboards or debugging overlays.</li>
    <li>Legacy DOM shims dispatch <code>paperscape:history</code> and <code>paperscape:command</code> events while also listening for legacy <code>paperscape:pushHistory</code> dispatches.</li>
    <li><code>commandBus.capturePointer()</code> and <code>captureSelection()</code> keep context records (pointer, selected IDs) synchronized so handlers always receive rich metadata.</li>
    <li>The core canvas registers as <em>PaperScape Core</em>, so deleting any item now pushes an undoable history entry and queued delete/undo/redo commands execute automatically.</li>
    <li>The Database Model View app now emits delta-based history entries for schema resets, table edits/moves, and foreign key deletes so undo/redo (and queue subscribers) only move the changed fragments.</li>
    <li>Floating undo/redo buttons render at the bottom of the viewport, subscribe to the command bus for enable states, and dispatch undo/redo without needing keyboard shortcuts.</li>
  </ul>
  <p><code>/OpenForum/AddOn/PaperScape/paperscape-queue.js</code> now includes <code>sendCommand</code>, <code>requestDelete</code>, <code>requestUndo</code>, <code>requestRedo</code>, and <code>pushHistoryEntry</code> helpers so remote services can submit edits via the same IntraQ channel.</p>
  <h3>TypeScript Definitions</h3>
  <p><code>/OpenForum/AddOn/PaperScape/commandBus.d.ts</code> declares <code>PaperScapeCommandBus</code>, participant handles, and strongly typed history entry contracts so TypeScript apps can import ambient definitions.</p>
  <pre class="doc-code"><code class="language-ts">const handle = PaperScapeCommandBus.registerCommandParticipant({
  id: "ObjectModeler",
  commands: ["delete", "undo", "redo"],
  onCommand(command, context) {
    if (command === "delete" &amp;&amp; context.selection?.length) {
      removeEntity(context.selection[0]?.id);
    }
  }
});

handle.pushHistoryEntry({
  id: "obj.delete-field",
  label: "Delete Field",
  payload: { entityId, fieldId },
  undo: "obj.restore-field",
  redo(context) {
    deleteField(context.payload.fieldId);
  }
});

PaperScapeCommandBus.onHistoryEvent((event, entry) => {
  if (event === "telemetry") console.debug("[CmdBus]", entry);
});</code></pre>
  <h3>Remote Queue Example</h3>
  <pre class="doc-code"><code>const queue = new PaperScapeQueue({ appName: "MCPAgent", auth: { token: "bearer abc123" } });
queue.requestDelete({ selection: [{ id: "db.User" }] });
queue.pushHistoryEntry({
  id: "mcp.update-name",
  label: "Rename Entity",
  undoCommand: "objectmodel.undo-rename",
  redoCommand: "objectmodel.redo-rename",
  payload: { entityId: "db.User", previous: "User", next: "Users" }
});</code></pre>
  <h3>Vanilla JS Example</h3>
  <pre class="doc-code"><code>const undoHandle = PaperScapeCommandBus.registerCommandParticipant({
  id: "Whiteboard",
  onCommand(command, ctx) {
    if (command === "undo") {
      replayStroke(ctx);
    }
  }
});

document.addEventListener("paperscape:history", (evt) => {
  const { event, entry } = evt.detail;
  if (event === "push") {
    console.info("Stack updated:", entry.label);
  }
});</code></pre>
  <h3>Legacy DOM Signals</h3>
  <p>Older modules can emit <code>paperscape:pushHistory</code> or <code>paperscape:command</code> events instead of calling the JS API directly.</p>
  <pre class="doc-code"><code>document.dispatchEvent(new CustomEvent("paperscape:pushHistory", {
  detail: {
    entry: {
      id: "legacy.move",
      label: "Move Anchor",
      undo: "legacy.move.undo",
      redo: "legacy.move.redo"
    }
  }
}));</code></pre>
  <h3>Collaboration Queue Bridge</h3>
  <p><code>/OpenForum/AddOn/PaperScape/collaboration-bridge.js</code> links the server-side <code>/OpenForum/MessageQueue</code> service with PaperScape’s IntraQ channel. The bridge polls the per-user queue at <code>/OpenForum/Users/&lt;user&gt;/CollaborationQueue</code>, forwards messages tagged with <code>channel: "collaboration"</code> into the PaperScape command bus, and republishes local history pushes back to the queue so MCP agents see the same deltas.</p>
  <p>Collaboration envelopes follow <code>/OpenForum/AddOn/PaperScape/collaboration-schema.json</code>. A short guide is available at <code>/OpenForum/AddOn/PaperScape/collaboration-guide.md</code>.</p>
  <pre class="doc-code"><code>OpenForum.includeScript("/OpenForum/MessageQueue/MessageQueue.js");
OpenForum.loadScript("/OpenForum/AddOn/PaperScape/paperscape-queue.js");
OpenForum.loadScript("/OpenForum/AddOn/PaperScape/collaboration-bridge.js");

var bridge = new PaperScapeCollaborationBridge({
  serverQueue: "/OpenForum/Users/Guest/CollaborationQueue",
  channel: "collaboration",
  instanceId: "PaperScapeClient-" + Math.random().toString(36).slice(2),
  paperQueueOptions: { appName: "PaperScapeCollab" }
});</code></pre>
  <p>Remote agents send JSON messages to the shared queue using the same channel. The bridge ignores its own origin ids so it is safe to publish/receive in the same session.</p>
  <pre class="doc-code"><code>{
  "schema": "/OpenForum/AddOn/PaperScape/collaboration-schema.json",
  "schemaVersion": "1.0",
  "channel": "collaboration",
  "origin": "mcp-agent",
  "messageType": "history-entry",
  "packet": {
    "action": "history-entry",
    "entry": {
      "id": "dbmv.move-173238",
      "label": "Move users",
      "payload": { ... delta ... }
    }
  }
}</code></pre>
  <p>The same module can be reused by other collaborative apps (e.g., document editors) by instantiating it with a different channel string.</p>
  <p>For MCP agents, use the <code>paperscape_queue</code> tool (under <code>/OpenForum/AddOn/ClaudeMCP</code>) to push or pull JSON envelopes from <code>/OpenForum/Users/&lt;user&gt;/CollaborationQueue</code>. The tool automatically prefixes messages with the <code>origin:</code> header expected by <code>MessageQueue.js</code>.</p>
</section>

<section id="next-steps">
  <h2 class="doc-section-title">10. Next Steps</h2>
  <ul>
    <li>Exercise regression coverage for the updated registration, naming, and removal flow across saved scenes.</li>
    <li>Add a "New Scene" or "Clear Canvas" action before loading new JSON.</li>
    <li>Surface this documentation and quick references directly inside the PaperScape UI.</li>
  </ul>
</section>
