@wasm-gaming/engine-specs 0.2.3 → 0.2.5
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.
- package/demo/README.md +75 -22
- package/demo/components/drop-area.html +54 -7
- package/demo/components/esc-menu.html +540 -0
- package/demo/components/launcher.html +46 -24
- package/demo/components/sdk-info.html +14 -2
- package/demo/demo.css +6 -1
- package/demo/demo.js +579 -121
- package/demo/demo.sdk.js +4 -1
- package/demo/index.html +58 -1
- package/package.json +1 -1
- package/demo/components/file-info.html +0 -66
package/demo/README.md
CHANGED
|
@@ -6,19 +6,75 @@ This directory contains a standalone, themable web interface template for hostin
|
|
|
6
6
|
|
|
7
7
|
1. **Copy the `demo/` folder** into your engine repository.
|
|
8
8
|
|
|
9
|
-
2. **
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
2. **Initialize via ES module script**:
|
|
10
|
+
```html
|
|
11
|
+
<script type="module">
|
|
12
|
+
import demo from './demo.js'
|
|
13
|
+
import sdk from './demo.sdk.js' // Or your engine SDK import
|
|
14
|
+
|
|
15
|
+
demo
|
|
16
|
+
.init({
|
|
17
|
+
messages: {
|
|
18
|
+
title: 'My Custom Engine Demo',
|
|
19
|
+
},
|
|
20
|
+
bios: false, // 'required' | 'optional' | false
|
|
21
|
+
escMenu: {
|
|
22
|
+
enabled: true,
|
|
23
|
+
title: 'Game Pause Menu',
|
|
24
|
+
items: [
|
|
25
|
+
{ label: 'Toggle Fullscreen', action: (instance) => { document.documentElement.requestFullscreen?.(); } }
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
.on('file', ({ type, action, file }) => {
|
|
30
|
+
if (file) {
|
|
31
|
+
console.log(`[Demo] Selected ${type} file: ${file.name}`)
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
.on('launch', async (e) => {
|
|
35
|
+
const assets = {}
|
|
36
|
+
|
|
37
|
+
// if rom loaded
|
|
38
|
+
if (demo.hasFile('rom')) {
|
|
39
|
+
assets.rom = await demo.loadToMEMFS('rom')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// if bios required and loaded
|
|
43
|
+
if (demo.hasFile('bios')) {
|
|
44
|
+
assets.bios = await demo.loadToMEMFS('bios')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const instance = await sdk.load({
|
|
48
|
+
attachTo: e.attachTo,
|
|
49
|
+
assets,
|
|
50
|
+
options: { fileName: e.fileName, byteLength: e.byteLength },
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
instance.start()
|
|
54
|
+
return instance
|
|
55
|
+
})
|
|
56
|
+
</script>
|
|
17
57
|
```
|
|
18
|
-
*Alternatively*, if embedding in HTML without modifying `sdk.js`, set `window.SDK = myEngineSdk;` before `demo.js` runs.
|
|
19
58
|
|
|
20
|
-
|
|
21
|
-
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 🎮 Component79 ESC Menu
|
|
62
|
+
|
|
63
|
+
The demo includes an interactive, customizable in-game ESC pause menu component built with **Component79**.
|
|
64
|
+
|
|
65
|
+
### ESC Menu Options (`escMenu`)
|
|
66
|
+
|
|
67
|
+
| Option | Type | Default | Description |
|
|
68
|
+
|---|---|---|---|
|
|
69
|
+
| `enabled` | `boolean` | `true` | Enable/disable in-game ESC menu overlay. |
|
|
70
|
+
| `title` | `string` | `"Game Menu"` | Title displayed at top of ESC menu modal. |
|
|
71
|
+
| `shortcutKey` | `string` | `"Escape"` | Keyboard key that toggles the menu overlay. |
|
|
72
|
+
| `showTriggerButton` | `boolean` | `true` | Display floating top-right "ESC Menu" trigger badge for mouse/touch access. |
|
|
73
|
+
| `items` | `Array<{label: string, action: function}>` | `[]` | Custom action buttons added to ESC menu. |
|
|
74
|
+
| `onReset` | `function` | `instance.reset()` | Callback when Reset Game button is pressed. |
|
|
75
|
+
| `onExit` | `function` | `instance.destroy()` | Callback when Exit to Launcher button is pressed. |
|
|
76
|
+
| `onSaveState` | `function` | `instance.saveState()` | Callback when Save State button is pressed. |
|
|
77
|
+
| `onLoadState` | `function` | `instance.loadState()` | Callback when Load State button is pressed. |
|
|
22
78
|
|
|
23
79
|
---
|
|
24
80
|
|
|
@@ -50,15 +106,10 @@ To apply your custom branding, override any of the `:root` variables in `demo.cs
|
|
|
50
106
|
--demo-subpanel-bg: rgba(30, 41, 59, 0.6);
|
|
51
107
|
--demo-subpanel-border: rgba(255, 255, 255, 0.1);
|
|
52
108
|
|
|
53
|
-
/*
|
|
54
|
-
--demo-
|
|
55
|
-
--demo-
|
|
56
|
-
--demo-
|
|
57
|
-
--demo-picker-text: #ffffff;
|
|
58
|
-
|
|
59
|
-
/* Launch button */
|
|
60
|
-
--demo-launch-bg: var(--demo-accent);
|
|
61
|
-
--demo-launch-text: #ffffff;
|
|
109
|
+
/* ESC Menu styling */
|
|
110
|
+
--demo-esc-bg: rgba(6, 9, 16, 0.85);
|
|
111
|
+
--demo-esc-card-bg: rgba(15, 23, 42, 0.9);
|
|
112
|
+
--demo-esc-text: #f8fafc;
|
|
62
113
|
}
|
|
63
114
|
```
|
|
64
115
|
|
|
@@ -84,8 +135,9 @@ To apply your custom branding, override any of the `:root` variables in `demo.cs
|
|
|
84
135
|
| `--demo-picker-bg` | Pick File button background | `rgba(255, 255, 255, 0.5)` |
|
|
85
136
|
| `--demo-pill-bg` | Metadata badge background | `rgba(var(--demo-accent-rgb), 0.1)` |
|
|
86
137
|
| `--demo-file-info-bg` | Canvas overlay panel background | `rgba(255, 255, 255, 0.7)` |
|
|
87
|
-
| `--demo-
|
|
88
|
-
| `--demo-
|
|
138
|
+
| `--demo-esc-bg` | ESC menu overlay background | `rgba(6, 9, 16, 0.82)` |
|
|
139
|
+
| `--demo-esc-card-bg` | ESC menu card background | `rgba(15, 23, 42, 0.88)` |
|
|
140
|
+
| `--demo-esc-text` | ESC menu text color | `#f8fafc` |
|
|
89
141
|
| `--demo-font-sans` | Primary sans-serif font family | `"Outfit", system-ui, sans-serif` |
|
|
90
142
|
| `--demo-font-mono` | Monospace code font family | `"Space Mono", monospace` |
|
|
91
143
|
|
|
@@ -93,6 +145,7 @@ To apply your custom branding, override any of the `:root` variables in `demo.cs
|
|
|
93
145
|
|
|
94
146
|
## 🛠 Features
|
|
95
147
|
|
|
148
|
+
- **Component79 ESC Menu**: Customizable pause menu overlay with keydown listeners and touch/mouse badges.
|
|
96
149
|
- **OPFS Asset Persistence**: Automatically stores selected ROM and BIOS files in the Origin Private File System (`navigator.storage.getDirectory()`), restoring them automatically across page reloads.
|
|
97
150
|
- **Split Asset Drop Zones**: Independent drop/picker areas for optional **BIOS** firmware and game **ROM** assets.
|
|
98
151
|
- **Dedicated Launch Trigger**: Prominent launch button that activates once required game assets are selected.
|
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
@dragleave="dragging = false"
|
|
4
4
|
@drop.prevent="onDrop">
|
|
5
5
|
<strong>{{ prompt }}</strong>
|
|
6
|
-
<p :class.file-selected="selectedName">{{ selectedName ? 'Selected: ' + selectedName : assetHint }}</p>
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
<p :class.file-selected="selectedName">{{ selectedName ? ((messages.selectedPrefix || 'Selected: ') + selectedName) : assetHint }}</p>
|
|
7
|
+
<div class="picker-actions">
|
|
8
|
+
<label class="picker">
|
|
9
|
+
{{ selectedName ? (messages.changeFileButton || '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
|
+
{{ messages.removeFileButton || 'Remove' }}
|
|
14
|
+
</button>
|
|
15
|
+
</div>
|
|
11
16
|
</section>
|
|
12
17
|
|
|
13
18
|
<script :setup="{
|
|
@@ -16,6 +21,7 @@
|
|
|
16
21
|
accept,
|
|
17
22
|
buttonText = 'Pick file',
|
|
18
23
|
fileName = '',
|
|
24
|
+
messages = {},
|
|
19
25
|
}">
|
|
20
26
|
let dragging = false;
|
|
21
27
|
let selectedName = fileName || "";
|
|
@@ -30,7 +36,12 @@
|
|
|
30
36
|
};
|
|
31
37
|
|
|
32
38
|
const emitFile = (file) => {
|
|
33
|
-
if (!file)
|
|
39
|
+
if (!file) {
|
|
40
|
+
selectedName = "";
|
|
41
|
+
$emit("remove");
|
|
42
|
+
$emit("select", null);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
34
45
|
selectedName = file.name;
|
|
35
46
|
$emit("select", file);
|
|
36
47
|
};
|
|
@@ -45,6 +56,12 @@
|
|
|
45
56
|
const file = extractFile(event);
|
|
46
57
|
if (file) emitFile(file);
|
|
47
58
|
};
|
|
59
|
+
|
|
60
|
+
const onRemove = () => {
|
|
61
|
+
selectedName = "";
|
|
62
|
+
$emit("remove");
|
|
63
|
+
$emit("select", null);
|
|
64
|
+
};
|
|
48
65
|
</script>
|
|
49
66
|
|
|
50
67
|
<style>
|
|
@@ -94,9 +111,15 @@
|
|
|
94
111
|
font-weight: 600;
|
|
95
112
|
}
|
|
96
113
|
|
|
97
|
-
.picker {
|
|
114
|
+
.picker-actions {
|
|
98
115
|
display: inline-flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
gap: 0.5rem;
|
|
99
118
|
margin-top: 1rem;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.picker {
|
|
122
|
+
display: inline-flex;
|
|
100
123
|
background: var(--demo-picker-bg, rgba(255, 255, 255, 0.5));
|
|
101
124
|
color: var(--demo-picker-text, var(--demo-text, #0f172a));
|
|
102
125
|
border: 1px solid var(--demo-picker-border, rgba(255, 255, 255, 0.6));
|
|
@@ -121,4 +144,28 @@
|
|
|
121
144
|
.picker input {
|
|
122
145
|
display: none;
|
|
123
146
|
}
|
|
147
|
+
|
|
148
|
+
.remove-btn {
|
|
149
|
+
display: inline-flex;
|
|
150
|
+
align-items: center;
|
|
151
|
+
background: rgba(239, 68, 68, 0.15);
|
|
152
|
+
color: #ef4444;
|
|
153
|
+
border: 1px solid rgba(239, 68, 68, 0.4);
|
|
154
|
+
border-radius: var(--demo-subpanel-radius, 8px);
|
|
155
|
+
padding: 0.5rem 0.8rem;
|
|
156
|
+
cursor: pointer;
|
|
157
|
+
text-transform: uppercase;
|
|
158
|
+
font-weight: 600;
|
|
159
|
+
font-size: 0.85rem;
|
|
160
|
+
letter-spacing: 0.05em;
|
|
161
|
+
transition: all 0.2s;
|
|
162
|
+
backdrop-filter: blur(var(--demo-subpanel-blur, 12px));
|
|
163
|
+
-webkit-backdrop-filter: blur(var(--demo-subpanel-blur, 12px));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.remove-btn:hover {
|
|
167
|
+
background: rgba(239, 68, 68, 0.3);
|
|
168
|
+
border-color: rgba(239, 68, 68, 0.8);
|
|
169
|
+
color: #dc2626;
|
|
170
|
+
}
|
|
124
171
|
</style>
|