@wasm-gaming/engine-specs 0.2.7 → 0.3.0
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/README.md +63 -54
- package/demo/app.html +227 -0
- package/demo/canvas-renderer.js +153 -0
- package/demo/components/asset-picker.html +137 -0
- package/demo/components/call-log.html +33 -0
- package/demo/components/engine-header.html +78 -0
- package/demo/components/lifecycle-bar.html +69 -0
- package/demo/components/property-table.html +119 -0
- package/demo/demo.css +26 -130
- package/demo/demo.sdk.js +405 -203
- package/demo/index.html +7 -56
- package/demo/tsconfig.json +17 -0
- package/dist/engine-specs.d.ts +99 -0
- package/dist/engine-specs.d.ts.map +1 -0
- package/dist/engine-specs.js +3 -0
- package/dist/engine-specs.js.map +1 -0
- package/package.json +7 -12
- package/src/engine-specs.ts +110 -0
- package/demo/README.md +0 -155
- package/demo/checksums.js +0 -101
- package/demo/components/drop-area.html +0 -171
- package/demo/components/esc-menu.html +0 -540
- package/demo/components/launcher.html +0 -220
- package/demo/components/sdk-info.html +0 -54
- package/demo/demo.js +0 -622
- package/demo/sdk.js +0 -19
- package/demo/storage.js +0 -88
- package/dist/engine.d.ts +0 -427
- package/dist/engine.d.ts.map +0 -1
- package/dist/engine.js +0 -83
- package/dist/engine.js.map +0 -1
- package/dist/index.d.ts +0 -13
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -12
- package/dist/index.js.map +0 -1
- package/dist/manifest.d.ts +0 -69
- package/dist/manifest.d.ts.map +0 -1
- package/dist/manifest.js +0 -8
- package/dist/manifest.js.map +0 -1
- package/dist/validate.d.ts +0 -10
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js +0 -79
- package/dist/validate.js.map +0 -1
- package/schema/engine-manifest.schema.json +0 -74
- package/src/engine.ts +0 -516
- package/src/index.ts +0 -55
- package/src/manifest.ts +0 -82
- package/src/validate.ts +0 -92
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Every contract call the page makes, newest first — so the chain is readable while
|
|
3
|
+
it runs, and `sdk.mount(stage).start()` is visibly one expression.
|
|
4
|
+
-->
|
|
5
|
+
<div class="log">
|
|
6
|
+
<div :each="(entry, index) in entries" :class.head="index === 0">{{ entry }}</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<script :setup="{
|
|
10
|
+
entries = [],
|
|
11
|
+
}">
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<style>
|
|
15
|
+
.log {
|
|
16
|
+
font-family: var(--mono, monospace);
|
|
17
|
+
font-size: 0.75rem;
|
|
18
|
+
color: var(--muted, #64748b);
|
|
19
|
+
max-height: 240px;
|
|
20
|
+
overflow-y: auto;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.log div {
|
|
24
|
+
padding: 0.2rem 0;
|
|
25
|
+
border-top: 1px solid var(--border, #e2e8f0);
|
|
26
|
+
word-break: break-all;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.log div.head {
|
|
30
|
+
color: var(--text, #0f172a);
|
|
31
|
+
border-top: 0;
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The engine's identity, read off the class before anything is constructed.
|
|
3
|
+
|
|
4
|
+
This is what replaced the manifest: `id`, `version`, `name` and `description` are
|
|
5
|
+
static members of the SDK constructor, so a launcher can list engines without
|
|
6
|
+
booting one.
|
|
7
|
+
-->
|
|
8
|
+
<header>
|
|
9
|
+
<div>
|
|
10
|
+
<h1>{{ name }} <code>{{ id }}</code></h1>
|
|
11
|
+
<p>{{ description }}</p>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="right">
|
|
14
|
+
<span class="pill">v{{ version }}</span>
|
|
15
|
+
<a class="pill link" :href="referenceHref">API reference</a>
|
|
16
|
+
</div>
|
|
17
|
+
</header>
|
|
18
|
+
|
|
19
|
+
<script :setup="{
|
|
20
|
+
name,
|
|
21
|
+
id,
|
|
22
|
+
version,
|
|
23
|
+
description = '',
|
|
24
|
+
referenceHref = '../',
|
|
25
|
+
}">
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<style>
|
|
29
|
+
header {
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-wrap: wrap;
|
|
32
|
+
gap: 1rem;
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: space-between;
|
|
35
|
+
padding: 1.25rem 1.5rem;
|
|
36
|
+
border-bottom: 1px solid var(--border, #e2e8f0);
|
|
37
|
+
background: var(--panel, #fff);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
h1 {
|
|
41
|
+
margin: 0;
|
|
42
|
+
font-size: 1.25rem;
|
|
43
|
+
letter-spacing: 0.02em;
|
|
44
|
+
color: var(--text, #0f172a);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
code {
|
|
48
|
+
font-family: var(--mono, monospace);
|
|
49
|
+
font-size: 0.75em;
|
|
50
|
+
color: var(--muted, #64748b);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
p {
|
|
54
|
+
margin: 0.25rem 0 0;
|
|
55
|
+
color: var(--muted, #64748b);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.right {
|
|
59
|
+
display: flex;
|
|
60
|
+
gap: 0.5rem;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.pill {
|
|
64
|
+
border: 1px solid var(--accent, #ff007f);
|
|
65
|
+
border-radius: 2px;
|
|
66
|
+
padding: 0.25rem 0.6rem;
|
|
67
|
+
font-family: var(--mono, monospace);
|
|
68
|
+
font-size: 0.78rem;
|
|
69
|
+
color: var(--accent, #ff007f);
|
|
70
|
+
background: rgb(255 0 127 / 0.08);
|
|
71
|
+
text-transform: uppercase;
|
|
72
|
+
white-space: nowrap;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.link {
|
|
76
|
+
text-decoration: none;
|
|
77
|
+
}
|
|
78
|
+
</style>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The lifecycle verbs, labelled with the call each one makes.
|
|
3
|
+
|
|
4
|
+
`pause` and `resume` are drawn differently on purpose: they are not in the
|
|
5
|
+
contract. This engine adds them, and a host driving a different engine may not
|
|
6
|
+
assume they exist.
|
|
7
|
+
-->
|
|
8
|
+
<div class="bar">
|
|
9
|
+
<button @click="$emit('start')" :disabled="running">start()</button>
|
|
10
|
+
<button @click="$emit('restart')" :disabled="!running">restart()</button>
|
|
11
|
+
<button class="extra" @click="$emit('pause')" :disabled="!running">pause()</button>
|
|
12
|
+
<button class="extra" @click="$emit('resume')" :disabled="!running">resume()</button>
|
|
13
|
+
<button @click="$emit('destroy')" :disabled="!running">destroy()</button>
|
|
14
|
+
</div>
|
|
15
|
+
<p class="hint"><span class="extra-dot"></span> beyond the contract — this engine's own members</p>
|
|
16
|
+
|
|
17
|
+
<script :setup="{
|
|
18
|
+
running = false,
|
|
19
|
+
}">
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<style>
|
|
23
|
+
.bar {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-wrap: wrap;
|
|
26
|
+
gap: 0.4rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
button {
|
|
30
|
+
font-family: var(--mono, monospace);
|
|
31
|
+
font-size: 0.8rem;
|
|
32
|
+
padding: 0.4rem 0.7rem;
|
|
33
|
+
border: 1px solid var(--border, #e2e8f0);
|
|
34
|
+
border-radius: 3px;
|
|
35
|
+
background: transparent;
|
|
36
|
+
color: var(--text, #0f172a);
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
button:hover:not(:disabled) {
|
|
41
|
+
border-color: var(--accent, #ff007f);
|
|
42
|
+
color: var(--accent, #ff007f);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
button:disabled {
|
|
46
|
+
opacity: 0.35;
|
|
47
|
+
cursor: default;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
button.extra,
|
|
51
|
+
.extra-dot {
|
|
52
|
+
border-style: dashed;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.hint {
|
|
56
|
+
margin: 0.75rem 0 0;
|
|
57
|
+
font-size: 0.8rem;
|
|
58
|
+
color: var(--muted, #64748b);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.extra-dot {
|
|
62
|
+
display: inline-block;
|
|
63
|
+
width: 0.7rem;
|
|
64
|
+
height: 0.7rem;
|
|
65
|
+
border: 1px dashed var(--muted, #64748b);
|
|
66
|
+
border-radius: 2px;
|
|
67
|
+
vertical-align: -1px;
|
|
68
|
+
}
|
|
69
|
+
</style>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
What the four getters return, rendered as-is.
|
|
3
|
+
|
|
4
|
+
This component is the argument for the descriptor: it is written once and paints
|
|
5
|
+
`config()`, `options()`, `assets()` and `storage()` alike, for any engine, without
|
|
6
|
+
knowing a single key name. Labels, defaults, allowed values and whether a property
|
|
7
|
+
can change on a running engine all travel with the value.
|
|
8
|
+
-->
|
|
9
|
+
<div class="tables">
|
|
10
|
+
<section class="props" :each="(table, tableIndex) in tables">
|
|
11
|
+
<h3>{{ table.title }}<span class="paren">()</span></h3>
|
|
12
|
+
<table>
|
|
13
|
+
<tr :each="(row, index) in table.rows">
|
|
14
|
+
<th>
|
|
15
|
+
{{ row.key }}
|
|
16
|
+
<span :if="row.live" class="live" title="Can be changed on a running engine">live</span>
|
|
17
|
+
</th>
|
|
18
|
+
<td class="value" :class.unset="row.unset">{{ row.value }}</td>
|
|
19
|
+
<td class="meta">
|
|
20
|
+
<span :if="row.description">{{ row.description }}</span>
|
|
21
|
+
<span :if="row.default" class="aside">default: {{ row.default }}</span>
|
|
22
|
+
<span :if="row.enum" class="aside">one of: {{ row.enum }}</span>
|
|
23
|
+
<span :if="row.allowedTypes" class="aside">accepts: {{ row.allowedTypes }}</span>
|
|
24
|
+
</td>
|
|
25
|
+
</tr>
|
|
26
|
+
</table>
|
|
27
|
+
</section>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<script :setup="{
|
|
31
|
+
tables = [],
|
|
32
|
+
}">
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<style>
|
|
36
|
+
.tables {
|
|
37
|
+
display: grid;
|
|
38
|
+
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
|
39
|
+
gap: 1rem;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.props {
|
|
43
|
+
background: var(--panel, #fff);
|
|
44
|
+
border: 1px solid var(--border, #e2e8f0);
|
|
45
|
+
border-radius: 4px;
|
|
46
|
+
padding: 1rem;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
h3 {
|
|
50
|
+
margin: 0 0 0.75rem;
|
|
51
|
+
font-size: 0.78rem;
|
|
52
|
+
font-family: var(--mono, monospace);
|
|
53
|
+
text-transform: uppercase;
|
|
54
|
+
letter-spacing: 0.08em;
|
|
55
|
+
color: var(--accent, #ff007f);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.paren {
|
|
59
|
+
color: var(--muted, #64748b);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
table {
|
|
63
|
+
width: 100%;
|
|
64
|
+
border-collapse: collapse;
|
|
65
|
+
font-size: 0.82rem;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
th,
|
|
69
|
+
td {
|
|
70
|
+
text-align: left;
|
|
71
|
+
vertical-align: top;
|
|
72
|
+
padding: 0.4rem 0.5rem 0.4rem 0;
|
|
73
|
+
border-top: 1px solid var(--border, #e2e8f0);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
tr:first-child th,
|
|
77
|
+
tr:first-child td {
|
|
78
|
+
border-top: 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
th {
|
|
82
|
+
font-family: var(--mono, monospace);
|
|
83
|
+
font-weight: 600;
|
|
84
|
+
white-space: nowrap;
|
|
85
|
+
color: var(--text, #0f172a);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.value {
|
|
89
|
+
font-family: var(--mono, monospace);
|
|
90
|
+
color: var(--accent, #ff007f);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.value.unset {
|
|
94
|
+
color: var(--muted, #64748b);
|
|
95
|
+
opacity: 0.6;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.meta {
|
|
99
|
+
color: var(--muted, #64748b);
|
|
100
|
+
font-size: 0.78rem;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.aside {
|
|
104
|
+
display: block;
|
|
105
|
+
font-family: var(--mono, monospace);
|
|
106
|
+
opacity: 0.75;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.live {
|
|
110
|
+
display: inline-block;
|
|
111
|
+
margin-left: 0.4rem;
|
|
112
|
+
padding: 0 0.3rem;
|
|
113
|
+
font-size: 0.62rem;
|
|
114
|
+
text-transform: uppercase;
|
|
115
|
+
border: 1px solid var(--accent, #ff007f);
|
|
116
|
+
border-radius: 2px;
|
|
117
|
+
color: var(--accent, #ff007f);
|
|
118
|
+
}
|
|
119
|
+
</style>
|
package/demo/demo.css
CHANGED
|
@@ -1,142 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
/*
|
|
2
|
+
Page shell only: the palette and the reset.
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
--demo-bg-gradient: linear-gradient(145deg, var(--demo-bg-a) 0%, var(--demo-bg-b) 100%);
|
|
8
|
-
--demo-bg-radial-1: rgba(255, 0, 127, 0.08);
|
|
9
|
-
--demo-bg-radial-2: rgba(2, 132, 199, 0.12);
|
|
10
|
-
|
|
11
|
-
--demo-text: #0f172a;
|
|
12
|
-
--demo-muted: #475569;
|
|
13
|
-
|
|
14
|
-
--demo-accent: #ff007f;
|
|
15
|
-
--demo-accent-rgb: 255, 0, 127;
|
|
16
|
-
--demo-accent-glow: 0 0 15px rgba(var(--demo-accent-rgb), 0.3), 0 0 30px rgba(var(--demo-accent-rgb), 0.15);
|
|
17
|
-
|
|
18
|
-
--demo-accent2: #0284c7;
|
|
19
|
-
--demo-accent2-rgb: 2, 132, 199;
|
|
20
|
-
--demo-accent2-glow: 0 0 15px rgba(var(--demo-accent2-rgb), 0.3), 0 0 30px rgba(var(--demo-accent2-rgb), 0.15);
|
|
21
|
-
|
|
22
|
-
/* Glassmorphism & Panel System */
|
|
23
|
-
--demo-panel-bg: rgba(255, 255, 255, 0.25);
|
|
24
|
-
--demo-panel-border: rgba(255, 255, 255, 0.4);
|
|
25
|
-
--demo-panel-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5);
|
|
26
|
-
--demo-panel-blur: 24px;
|
|
27
|
-
--demo-panel-radius: 12px;
|
|
28
|
-
|
|
29
|
-
--demo-subpanel-bg: rgba(255, 255, 255, 0.35);
|
|
30
|
-
--demo-subpanel-border: rgba(255, 255, 255, 0.3);
|
|
31
|
-
--demo-subpanel-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.6);
|
|
32
|
-
--demo-subpanel-blur: 12px;
|
|
33
|
-
--demo-subpanel-radius: 8px;
|
|
34
|
-
|
|
35
|
-
/* Drop Zone */
|
|
36
|
-
--demo-drop-bg: rgba(255, 255, 255, 0.15);
|
|
37
|
-
--demo-drop-border: rgba(255, 255, 255, 0.6);
|
|
38
|
-
--demo-drop-active-bg: rgba(255, 255, 255, 0.4);
|
|
39
|
-
--demo-drop-active-border: var(--demo-accent2);
|
|
40
|
-
--demo-drop-active-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.8);
|
|
41
|
-
|
|
42
|
-
/* Button / File Picker */
|
|
43
|
-
--demo-picker-bg: rgba(255, 255, 255, 0.5);
|
|
44
|
-
--demo-picker-hover-bg: rgba(255, 255, 255, 0.8);
|
|
45
|
-
--demo-picker-border: rgba(255, 255, 255, 0.6);
|
|
46
|
-
--demo-picker-hover-border: rgba(255, 255, 255, 0.9);
|
|
47
|
-
--demo-picker-text: var(--demo-text);
|
|
48
|
-
|
|
49
|
-
/* Metadata Pills */
|
|
50
|
-
--demo-pill-bg: rgba(var(--demo-accent-rgb), 0.1);
|
|
51
|
-
--demo-pill-border: var(--demo-accent);
|
|
52
|
-
--demo-pill-text: var(--demo-accent);
|
|
53
|
-
--demo-pill-shadow: inset 0 0 5px rgba(var(--demo-accent-rgb), 0.3);
|
|
54
|
-
|
|
55
|
-
/* File Info Overlay */
|
|
56
|
-
--demo-file-info-bg: rgba(255, 255, 255, 0.7);
|
|
57
|
-
--demo-file-info-border: rgba(255, 255, 255, 0.8);
|
|
58
|
-
--demo-file-info-blur: 10px;
|
|
59
|
-
|
|
60
|
-
/* ESC Menu Styling */
|
|
61
|
-
--demo-esc-bg: rgba(0, 0, 0, 0.45);
|
|
62
|
-
--demo-esc-card-bg: rgba(15, 23, 42, 0.92);
|
|
63
|
-
--demo-esc-text: #f8fafc;
|
|
4
|
+
Layout and every panel's look live in the components — `app.html` owns the grid,
|
|
5
|
+
each child owns its own. These custom properties cross into them, so a component
|
|
6
|
+
inherits the theme without knowing this file exists.
|
|
7
|
+
*/
|
|
64
8
|
|
|
65
|
-
|
|
66
|
-
--
|
|
67
|
-
--
|
|
9
|
+
:root {
|
|
10
|
+
--bg: #f8fafc;
|
|
11
|
+
--panel: #ffffff;
|
|
12
|
+
--border: #e2e8f0;
|
|
13
|
+
--text: #0f172a;
|
|
14
|
+
--muted: #64748b;
|
|
15
|
+
--accent: #ff007f;
|
|
16
|
+
--mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
|
|
17
|
+
}
|
|
68
18
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
--accent2-glow: var(--demo-accent2-glow);
|
|
78
|
-
--font-sans: var(--demo-font-sans);
|
|
79
|
-
--font-mono: var(--demo-font-mono);
|
|
19
|
+
@media (prefers-color-scheme: dark) {
|
|
20
|
+
:root {
|
|
21
|
+
--bg: #060910;
|
|
22
|
+
--panel: #0f172a;
|
|
23
|
+
--border: #1e293b;
|
|
24
|
+
--text: #e2e8f0;
|
|
25
|
+
--muted: #94a3b8;
|
|
26
|
+
}
|
|
80
27
|
}
|
|
81
28
|
|
|
82
29
|
* {
|
|
83
30
|
box-sizing: border-box;
|
|
84
31
|
}
|
|
85
32
|
|
|
86
|
-
html,
|
|
87
33
|
body {
|
|
88
|
-
width: 100%;
|
|
89
|
-
height: 100%;
|
|
90
34
|
margin: 0;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
radial-gradient(circle at 85% 30%, var(--demo-bg-radial-2), transparent 50%),
|
|
95
|
-
var(--demo-bg-gradient);
|
|
96
|
-
background-attachment: fixed;
|
|
97
|
-
font-family: var(--demo-font-sans);
|
|
98
|
-
letter-spacing: 0.02em;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
main:not(.running)::after {
|
|
102
|
-
content: "";
|
|
103
|
-
position: fixed;
|
|
104
|
-
inset: 0;
|
|
105
|
-
background: linear-gradient(to bottom,
|
|
106
|
-
rgba(0, 0, 0, 0),
|
|
107
|
-
rgba(0, 0, 0, 0) 50%,
|
|
108
|
-
rgba(0, 0, 0, 0.02) 50%,
|
|
109
|
-
rgba(0, 0, 0, 0.02));
|
|
110
|
-
background-size: 100% 4px;
|
|
111
|
-
pointer-events: none;
|
|
112
|
-
z-index: 9999;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
main {
|
|
116
|
-
min-height: 100vh;
|
|
117
|
-
min-height: 100dvh;
|
|
118
|
-
display: grid;
|
|
119
|
-
place-items: center;
|
|
120
|
-
padding: 2rem;
|
|
121
|
-
position: relative;
|
|
122
|
-
z-index: 1;
|
|
35
|
+
background: var(--bg);
|
|
36
|
+
color: var(--text);
|
|
37
|
+
font: 15px/1.5 system-ui, -apple-system, sans-serif;
|
|
123
38
|
}
|
|
124
|
-
|
|
125
|
-
main.running {
|
|
126
|
-
padding: 0;
|
|
127
|
-
background: black;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.runtime {
|
|
131
|
-
position: relative;
|
|
132
|
-
aspect-ratio: 5 / 4;
|
|
133
|
-
overflow: hidden;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.runtime canvas {
|
|
137
|
-
aspect-ratio: 5 / 4;
|
|
138
|
-
width: min(100vw, calc(100vh * 5 / 4));
|
|
139
|
-
height: auto;
|
|
140
|
-
max-height: 100vh;
|
|
141
|
-
display: block;
|
|
142
|
-
}
|