Skip to content

Add ?load= URL param; update URL on ROM selection#61

Merged
mattgodbolt merged 3 commits intomainfrom
molty/url-load-param
Mar 3, 2026
Merged

Add ?load= URL param; update URL on ROM selection#61
mattgodbolt merged 3 commits intomainfrom
molty/url-load-param

Conversation

@mattgodbolt-molty
Copy link
Collaborator

(I'm Molty, an AI assistant acting on behalf of @mattgodbolt)

Adds shareable URLs for loaded ROMs.

What changed

  • ?load=FantasyZone2.sms — loads a named ROM from the roms/ directory on startup
  • Selecting a ROM from the list updates the URL to ?load=<name> via history.replaceState
  • Uploading a file updates the URL to ?b64sms=<data>&load=<filename> (preserves existing b64sms shareability, adds display name)
  • updateUrl(params) helper centralises all URL state; easy to extend with future params

Design notes

  • Uses replaceState not pushState — doesn't pollute browser history
  • parseQuery() already existed and handles both ?search and #hash — unchanged
  • b64sms existing behaviour preserved; ?load= is additive alongside it
  • ROM names are not validated against RomList — if a ROM file doesn't exist the emulator loads an empty ROM (same as current fallback behaviour)

Future params to consider

  • ?debug=1 — auto-open debugger
  • ?pc=0x1234 — breakpoint on load

Build ✅ · 1342 tests ✅

- ?load=FantasyZone2.sms loads a named ROM from the roms/ directory
- Selecting a ROM from the list updates the URL to ?load=<name>
- Uploading a file updates the URL to ?b64sms=<data>&load=<filename>
- ?b64sms= param preserves optional ?load= for the display name
- updateUrl() helper centralises all URL param management
- URL uses history.replaceState so back/forward nav isn't affected

Provides shareable URLs for any loaded ROM.

🤖 Generated by LLM (Claude, via OpenClaw)
src/main.js Outdated
const reader = new FileReader();
reader.onload = function () {
resetLoadAndStart(file.name, reader.result);
// Uploaded files use b64sms encoding for shareability
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is resetLoadAndStart now dead code? looks like you duplicated its work here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I'm Molty, an AI assistant acting on behalf of @mattgodbolt) Good catch — fixed. resetLoadAndStart now takes an optional urlParams arg; loadUploadFile passes { b64sms, load } through it rather than duplicating the logic.

Pass urlParams through resetLoadAndStart instead of duplicating
the reset/load/start logic in loadUploadFile.

🤖 Generated by LLM (Claude, via OpenClaw)
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds shareable, stateful URLs for ROM loading by introducing a ?load= parameter and centralizing URL updates via a helper, so ROM selection/upload is reflected in the address bar without adding history entries.

Changes:

  • Add updateUrl(params) helper to rewrite emulator-related URL params using history.replaceState.
  • Support loading a named ROM on startup via ?load=<romname>.
  • Preserve existing b64sms startup behavior while adding load=<filename> for uploaded ROM display names.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +19 to +28
function updateUrl(params) {
const url = new URL(window.location.href);
// Clear existing emulator params before setting new ones
for (const key of [...url.searchParams.keys()]) {
url.searchParams.delete(key);
}
for (const [key, val] of Object.entries(params)) {
if (val !== null) url.searchParams.set(key, val);
}
history.replaceState(null, "", url);
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updateUrl rewrites the query string but leaves url.hash intact. Since parseQuery() merges ?search and #hash with the hash taking precedence (hash is appended last), any existing #b64sms/#load will keep overriding the new query params on reload, making the URL updates ineffective for users coming from hash-based links. Consider clearing url.hash (or updating parseQuery precedence) when you switch to query-param based state.

Copilot uses AI. Check for mistakes.
src/main.js Outdated
const parsedQuery = parseQuery();
if (parsedQuery["b64sms"]) {
bus.loadRom("b64.sms", atob(parsedQuery["b64sms"]), debug_init);
const name = parsedQuery["load"] ?? "uploaded.sms";
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parsedQuery["load"] can be an empty string for URLs like ?load=. In that case this code will pass an empty filename into bus.loadRom, and updateUrl will persist load=; it likely should fall back to the default upload name (or ignore load) when the value is empty.

Suggested change
const name = parsedQuery["load"] ?? "uploaded.sms";
const name = parsedQuery["load"] || "uploaded.sms";

Copilot uses AI. Check for mistakes.
src/main.js Outdated
Comment on lines +152 to +155
} else if (parsedQuery["load"]) {
const name = parsedQuery["load"];
bus.loadRom(name, loadRomData(name), debug_init);
updateUrl({ load: name });
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name comes directly from the URL and is concatenated into the XHR path in loadRomData ("roms/" + name). With values like ../index.html this will request files outside the roms/ directory. If ?load= is meant to only support known ROMs, validate against RomList (or at least reject path separators / ..) before calling loadRomData.

Copilot uses AI. Check for mistakes.
- sanitizeRomName() validates ?load= against RomList (rejects unknown
  names and path traversal attempts like ../index.html)
- updateUrl() now clears url.hash so legacy #b64sms hash links don't
  take precedence over new query params on reload
- Use || not ?? for b64sms display name so empty string falls back

🤖 Generated by LLM (Claude, via OpenClaw)
@mattgodbolt mattgodbolt merged commit 41d6603 into main Mar 3, 2026
3 checks passed
@mattgodbolt mattgodbolt deleted the molty/url-load-param branch March 3, 2026 21:51
mattgodbolt-molty added a commit that referenced this pull request Mar 4, 2026
- Resolve main.js conflict: preserve sms.loadRom() from SMS branch,
  incorporate updateUrl/sanitizeRomName/?load= from #61
- SMS instance created in main.js (const sms = new SMS()) and passed
  to miracle_init(sms) — miracle.js no longer owns the singleton
- miracle.js: keeps SMS import for static constants (FRAMES_PER_SECOND
  etc.) but does not create an instance

Addresses Copilot review: PR description now matches reality — no
module-level singleton exports anywhere.

🤖 Generated by LLM (Claude, via OpenClaw)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants