External web tools (e.g., swtool) generate .sw files in memory and currently can only offer a download button. Scientists must download the file, then manually load it into Spacewalk — a two-step process. We want a single "Open in Spacewalk" button that pipes the in-memory file directly into Spacewalk.
| Option | Pros | Cons |
|---|---|---|
?file=<url> (already built) |
Simple | Requires the file to be hosted somewhere with a public URL; doesn't work for in-memory files |
postMessage |
No server needed; works cross-origin; seamless one-click UX; file never touches disk | Requires both apps to agree on a message protocol |
| Temporary upload to S3/etc. | Spacewalk side is trivial (?file=) |
Requires server infrastructure, adds latency, costs money |
| Local file round-trip | Works today | Two manual steps — not seamless |
postMessage is the best fit: no infrastructure, cross-origin capable, and both apps are browser-based.
Spacewalk's loading chain — ingestEnsemblePath() → ensembleManager.loadURL() → datasources — uses FileUtils.isFilePath() to distinguish File objects from URL strings and handles both transparently. No new loading path is needed. We just need to construct a File from the received bytes and hand it to the existing pipeline.
swtool Spacewalk
│ │
│ window.open('/spacewalk/') │
│ ──────────────────────────────────────► │
│ │
│ (init completes)│
│ │
│ postMessage({ type: 'spacewalk-ready' })│
│ ◄────────────────────────────────────── │
│ │
│ postMessage({ │
│ type: 'spacewalk-load', │
│ bytes: Uint8Array, │
│ filename: 'output.sw' │
│ }) │
│ ──────────────────────────────────────► │
│ │
│ (file loads, 3D │
│ structure renders)│
spacewalk-ready (Spacewalk → opener)
- Sent once after initialization completes
- Tells the opener that Spacewalk is ready to receive a file
- Contains no sensitive data
spacewalk-load (opener → Spacewalk)
- Carries the file payload
- Fields:
| Field | Type | Required | Description |
|---|---|---|---|
type |
string |
Yes | Must be 'spacewalk-load' |
bytes |
Uint8Array |
Yes | Raw file bytes |
filename |
string |
Yes | Filename with extension (e.g., 'output.sw'). Extension determines which datasource/parser is used. |
One file modified: js/app.js
In initialize(), after hideGlobalSpinner() and before the render loop:
- If
window.openerexists, post{ type: 'spacewalk-ready' }back to it - Register a
messageevent listener that:- Ignores messages without
type: 'spacewalk-load' - Validates
bytesis aUint8Arrayandfilenameis a string - Constructs a
Fileobject:new File([bytes], filename) - Calls
ingestEnsemblePath(file, '0', undefined)— the same path used by the local file picker - Posts
DidLoadEnsembleFileon the event bus
- Ignores messages without
No new files. No changes to datasources, parsers, scene management, or the ?file= URL parameter.
In src/ui.js showSuccess(), add an "Open in Spacewalk" button alongside the existing download link. On click:
window.open('https://aidenlab.org/spacewalk/')- Listen for the
spacewalk-readymessage - Send
{ type: 'spacewalk-load', bytes, filename }to the opened window
- The
spacewalk-readymessage uses'*'astargetOriginsince the opener could be any domain. This is safe because the message contains no sensitive data — it's just a readiness signal. - On receive, Spacewalk validates
data.type,data.bytes instanceof Uint8Array, andtypeof data.filename === 'string'before acting. - No origin allowlist is needed at this stage. The worst an attacker could do is load a file into your own local Spacewalk session — there's no write-back or data exfiltration vector.
- Share URL feature (
?spacewalkSessionURL=...) - Direct file URL feature (
?file=<url>) - Local file picker / drag-and-drop
- Datasource, parser, or scene management code
npm run build— no build errorsnpm run dev— open swtool in one tab, click "Open in Spacewalk", confirm the file loads and renders in the new tab- Confirm existing features (local file load, URL param, share URLs) still work