@wasm-gaming/engine-specs 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,10 +4,15 @@
4
4
  @drop.prevent="onDrop">
5
5
  <strong>{{ prompt }}</strong>
6
6
  <p :class.file-selected="selectedName">{{ selectedName ? 'Selected: ' + selectedName : assetHint }}</p>
7
- <label class="picker">
8
- {{ selectedName ? 'Change File' : buttonText }}
9
- <input type="file" :accept="accept" @change="onPick" />
10
- </label>
7
+ <div class="picker-actions">
8
+ <label class="picker">
9
+ {{ selectedName ? 'Change File' : buttonText }}
10
+ <input type="file" :accept="accept" @change="onPick" />
11
+ </label>
12
+ <button type="button" :if="selectedName" class="remove-btn" @click.stop="onRemove">
13
+ Remove
14
+ </button>
15
+ </div>
11
16
  </section>
12
17
 
13
18
  <script :setup="{
@@ -30,7 +35,12 @@
30
35
  };
31
36
 
32
37
  const emitFile = (file) => {
33
- if (!file) return;
38
+ if (!file) {
39
+ selectedName = "";
40
+ $emit("remove");
41
+ $emit("select", null);
42
+ return;
43
+ }
34
44
  selectedName = file.name;
35
45
  $emit("select", file);
36
46
  };
@@ -45,6 +55,12 @@
45
55
  const file = extractFile(event);
46
56
  if (file) emitFile(file);
47
57
  };
58
+
59
+ const onRemove = () => {
60
+ selectedName = "";
61
+ $emit("remove");
62
+ $emit("select", null);
63
+ };
48
64
  </script>
49
65
 
50
66
  <style>
@@ -94,9 +110,15 @@
94
110
  font-weight: 600;
95
111
  }
96
112
 
97
- .picker {
113
+ .picker-actions {
98
114
  display: inline-flex;
115
+ align-items: center;
116
+ gap: 0.5rem;
99
117
  margin-top: 1rem;
118
+ }
119
+
120
+ .picker {
121
+ display: inline-flex;
100
122
  background: var(--demo-picker-bg, rgba(255, 255, 255, 0.5));
101
123
  color: var(--demo-picker-text, var(--demo-text, #0f172a));
102
124
  border: 1px solid var(--demo-picker-border, rgba(255, 255, 255, 0.6));
@@ -121,4 +143,28 @@
121
143
  .picker input {
122
144
  display: none;
123
145
  }
146
+
147
+ .remove-btn {
148
+ display: inline-flex;
149
+ align-items: center;
150
+ background: rgba(239, 68, 68, 0.15);
151
+ color: #ef4444;
152
+ border: 1px solid rgba(239, 68, 68, 0.4);
153
+ border-radius: var(--demo-subpanel-radius, 8px);
154
+ padding: 0.5rem 0.8rem;
155
+ cursor: pointer;
156
+ text-transform: uppercase;
157
+ font-weight: 600;
158
+ font-size: 0.85rem;
159
+ letter-spacing: 0.05em;
160
+ transition: all 0.2s;
161
+ backdrop-filter: blur(var(--demo-subpanel-blur, 12px));
162
+ -webkit-backdrop-filter: blur(var(--demo-subpanel-blur, 12px));
163
+ }
164
+
165
+ .remove-btn:hover {
166
+ background: rgba(239, 68, 68, 0.3);
167
+ border-color: rgba(239, 68, 68, 0.8);
168
+ color: #dc2626;
169
+ }
124
170
  </style>
@@ -12,6 +12,7 @@
12
12
  :button-text="'Pick BIOS'"
13
13
  :file-name="biosFile?.name"
14
14
  @select="onBiosSelect"
15
+ @remove="onBiosRemove"
15
16
  />
16
17
  <CDropArea
17
18
  :prompt="'Drop ROM File'"
@@ -20,6 +21,7 @@
20
21
  :button-text="'Pick ROM'"
21
22
  :file-name="romFile?.name"
22
23
  @select="onRomSelect"
24
+ @remove="onRomRemove"
23
25
  />
24
26
  </div>
25
27
 
@@ -37,6 +39,8 @@
37
39
  onLaunchFiles,
38
40
  onSaveBios,
39
41
  onSaveRom,
42
+ onRemoveBios,
43
+ onRemoveRom,
40
44
  initialRomFile = null,
41
45
  initialBiosFile = null,
42
46
  romAccept,
@@ -44,7 +48,7 @@
44
48
  biosAccept,
45
49
  biosAssetHint = 'optional BIOS firmware file',
46
50
  requiresBIOS = false,
47
- showBIOS = true,
51
+ showBIOS = false,
48
52
  }">
49
53
  let romFile = initialRomFile;
50
54
  let biosFile = initialBiosFile;
@@ -77,7 +81,10 @@
77
81
 
78
82
  const onRomSelect = (arg) => {
79
83
  const file = extractFile(arg);
80
- if (!file) return;
84
+ if (!file) {
85
+ onRomRemove();
86
+ return;
87
+ }
81
88
  romFile = file;
82
89
  updateStatus();
83
90
  onSaveRom?.(file);
@@ -85,12 +92,27 @@
85
92
 
86
93
  const onBiosSelect = (arg) => {
87
94
  const file = extractFile(arg);
88
- if (!file) return;
95
+ if (!file) {
96
+ onBiosRemove();
97
+ return;
98
+ }
89
99
  biosFile = file;
90
100
  updateStatus();
91
101
  onSaveBios?.(file);
92
102
  };
93
103
 
104
+ const onRomRemove = () => {
105
+ romFile = null;
106
+ updateStatus();
107
+ onRemoveRom?.();
108
+ };
109
+
110
+ const onBiosRemove = () => {
111
+ biosFile = null;
112
+ updateStatus();
113
+ onRemoveBios?.();
114
+ };
115
+
94
116
  const onLaunch = async () => {
95
117
  if (!canLaunch) {
96
118
  updateStatus();
package/demo/demo.css CHANGED
@@ -93,7 +93,7 @@ body {
93
93
  letter-spacing: 0.02em;
94
94
  }
95
95
 
96
- body::after {
96
+ main:not(.running)::after {
97
97
  content: "";
98
98
  position: fixed;
99
99
  inset: 0;
package/demo/demo.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { getSdk } from "./sdk.js";
2
2
  import { checksumAlgorithms, computeChecksums } from "./checksums.js";
3
- import { loadStoredAsset, saveStoredAsset } from "./storage.js";
3
+ import { loadStoredAsset, saveStoredAsset, clearStoredAsset } from "./storage.js";
4
4
  import { $, $create, Component79 } from "https://jgermade.github.io/jq79/jq79.js";
5
5
 
6
6
  // Safe URL parameter resolution from script URL & page URL
@@ -34,10 +34,9 @@ if (sdk.manifest?.name) {
34
34
  const romSpec = sdk.manifest?.assets?.find((a) => a.key === "rom") ?? sdk.manifest?.assets?.[0];
35
35
  const biosSpec = sdk.manifest?.assets?.find((a) => a.key === "bios") ?? sdk.manifest?.assets?.[1];
36
36
 
37
- // Determine BIOS visibility and requirement rules
38
- const hasBiosSpec = Boolean(biosSpec);
39
- const showBIOS = biosParam !== "false" && (hasBiosSpec || biosParam === "required" || biosParam === "true" || biosParam === "optional");
40
- const requiresBIOS = biosParam === "required" || (biosParam !== "optional" && Boolean(biosSpec?.required));
37
+ // Determine BIOS visibility and requirement rules (Default: showBIOS = false)
38
+ const showBIOS = biosParam === "true" || biosParam === "optional" || biosParam === "required";
39
+ const requiresBIOS = biosParam === "required";
41
40
 
42
41
  // Load previously stored ROM & BIOS from OPFS if available
43
42
  const [storedRom, storedBios] = await Promise.all([
@@ -138,6 +137,8 @@ CLauncher
138
137
  initialBiosFile: storedBios,
139
138
  onSaveRom: (file) => saveStoredAsset("rom", file),
140
139
  onSaveBios: (file) => saveStoredAsset("bios", file),
140
+ onRemoveRom: () => clearStoredAsset("rom"),
141
+ onRemoveBios: () => clearStoredAsset("bios"),
141
142
  onLaunchFiles: bootWithFiles,
142
143
  romAccept,
143
144
  romAssetHint,
package/demo/demo.sdk.js CHANGED
@@ -21,7 +21,7 @@ export function createDummySdk() {
21
21
  mountPath: "/bios.bin",
22
22
  required: false,
23
23
  accept: [".bin", ".rom", ".sys"],
24
- description: "Optional system BIOS firmware file.",
24
+ description: "System BIOS firmware file.",
25
25
  },
26
26
  ],
27
27
  input: "keyboard-default",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wasm-gaming/engine-specs",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "The wasm-gaming engine contract: the single shared interface every WASM game/emulator engine and the host app conform to. TypeScript types + JSON Schema + a Zod runtime validator.",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",