@homie-rocks/studio 0.30.2 → 0.31.1
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/CHANGELOG.md +108 -1
- package/README.md +349 -23
- package/assets/animate.ts +16 -6
- package/assets/assets.ts +14 -3
- package/assets/render-page.ts +10 -2
- package/assets/safety.mjs +7 -1
- package/bin/homie-studio.mjs +204 -124
- package/lib/art-cli.mjs +61 -18
- package/lib/art-tools.mjs +53 -10
- package/lib/asset-check.mjs +249 -46
- package/lib/asset-import.mjs +11 -5
- package/lib/asset-manifest.mjs +128 -51
- package/lib/build.mjs +239 -72
- package/lib/characters.mjs +119 -20
- package/lib/check.mjs +110 -7
- package/lib/chrome.mjs +11 -0
- package/lib/clips.mjs +54 -0
- package/lib/cloudflare.mjs +203 -10
- package/lib/codex.mjs +6 -0
- package/lib/collision.mjs +245 -0
- package/lib/decisions.mjs +2 -2
- package/lib/deploy-state.mjs +166 -0
- package/lib/dev.mjs +430 -0
- package/lib/directory.mjs +172 -9
- package/lib/doctor.mjs +12 -11
- package/lib/handoff.mjs +2 -6
- package/lib/library.mjs +1 -1
- package/lib/mcp-tools.mjs +42 -37
- package/lib/mcp.mjs +1 -1
- package/lib/net.mjs +81 -2
- package/lib/node-version.mjs +40 -0
- package/lib/office.mjs +6 -6
- package/lib/optimise.mjs +39 -4
- package/lib/parts-build.mjs +169 -0
- package/lib/parts-cli.mjs +104 -0
- package/lib/parts-store.mjs +342 -0
- package/lib/parts-tools.mjs +92 -0
- package/lib/parts.mjs +720 -0
- package/lib/perf.mjs +131 -31
- package/lib/port-check.mjs +40 -6
- package/lib/preview.mjs +77 -0
- package/lib/routes.mjs +240 -0
- package/lib/scaffold.mjs +83 -22
- package/lib/shoot.mjs +307 -0
- package/lib/site.mjs +1 -2
- package/lib/stage.mjs +118 -0
- package/lib/studio.mjs +0 -66
- package/lib/style-board.mjs +49 -6
- package/lib/template-history.json +101 -0
- package/lib/trailer.mjs +47 -0
- package/lib/typecheck.mjs +107 -0
- package/mcp/ui/lineup.js +3 -3
- package/mcp/ui/rights.js +1 -3
- package/netplay/NETPLAY.md +552 -16
- package/netplay/netplay.ts +950 -43
- package/package.json +10 -1
- package/parts/PARTS.md +169 -0
- package/port/index.ts +8 -2
- package/port/personas.ts +275 -0
- package/port/powerups.ts +357 -0
- package/port/probe.ts +38 -2
- package/port/room.ts +329 -40
- package/site/SITE.md +102 -20
- package/starters/ember-vale/index.html +1 -1
- package/starters/ember-vale/src/main.ts +7 -1
- package/starters/gem-rush/index.html +1 -1
- package/starters/gem-rush/src/main.ts +41 -12
- package/starters/gem-rush-3d/assets/RIGHTS.md +0 -24
- package/starters/gem-rush-3d/assets/manifest.json +0 -24
- package/starters/gem-rush-3d/index.html +1 -1
- package/starters/gem-rush-3d/src/main.ts +50 -11
- package/starters/hero-rush-3d/assets/RIGHTS.md +0 -19
- package/starters/hero-rush-3d/assets/manifest.json +0 -19
- package/starters/hero-rush-3d/index.html +1 -1
- package/starters/hero-rush-3d/src/main.ts +50 -11
- package/worker/arrival.mjs +4 -1
- package/worker/discover.mjs +11 -25
- package/worker/index.mjs +142 -62
- package/worker/license.mjs +45 -41
- package/worker/office-page.mjs +0 -4
- package/worker/office-schema.mjs +6 -0
- package/worker/office.mjs +19 -23
- package/worker/pages.mjs +156 -29
- package/worker/parts.mjs +275 -0
- package/worker/room.mjs +157 -14
- package/worker/schema.mjs +6 -8
- package/worker/seats.mjs +71 -0
- package/worker/site.mjs +51 -53
- package/worker/version.mjs +1 -1
- package/lib/remix-assets.mjs +0 -84
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
}
|
|
30
30
|
],
|
|
31
31
|
"license": {
|
|
32
|
-
"remix": "include",
|
|
33
32
|
"kind": "cc0",
|
|
34
33
|
"spdx": "CC0-1.0",
|
|
35
34
|
"owner": "Kenney",
|
|
@@ -132,7 +131,6 @@
|
|
|
132
131
|
}
|
|
133
132
|
],
|
|
134
133
|
"license": {
|
|
135
|
-
"remix": "include",
|
|
136
134
|
"kind": "cc0",
|
|
137
135
|
"spdx": "CC0-1.0",
|
|
138
136
|
"owner": "Kenney",
|
|
@@ -236,7 +234,6 @@
|
|
|
236
234
|
}
|
|
237
235
|
],
|
|
238
236
|
"license": {
|
|
239
|
-
"remix": "include",
|
|
240
237
|
"kind": "cc0",
|
|
241
238
|
"spdx": "CC0-1.0",
|
|
242
239
|
"owner": "Kenney",
|
|
@@ -341,7 +338,6 @@
|
|
|
341
338
|
}
|
|
342
339
|
],
|
|
343
340
|
"license": {
|
|
344
|
-
"remix": "include",
|
|
345
341
|
"kind": "cc0",
|
|
346
342
|
"spdx": "CC0-1.0",
|
|
347
343
|
"owner": "Kenney",
|
|
@@ -446,7 +442,6 @@
|
|
|
446
442
|
}
|
|
447
443
|
],
|
|
448
444
|
"license": {
|
|
449
|
-
"remix": "include",
|
|
450
445
|
"kind": "cc0",
|
|
451
446
|
"spdx": "CC0-1.0",
|
|
452
447
|
"owner": "Kenney",
|
|
@@ -552,7 +547,6 @@
|
|
|
552
547
|
}
|
|
553
548
|
],
|
|
554
549
|
"license": {
|
|
555
|
-
"remix": "include",
|
|
556
550
|
"kind": "cc0",
|
|
557
551
|
"spdx": "CC0-1.0",
|
|
558
552
|
"owner": "Kenney",
|
|
@@ -658,7 +652,6 @@
|
|
|
658
652
|
}
|
|
659
653
|
],
|
|
660
654
|
"license": {
|
|
661
|
-
"remix": "include",
|
|
662
655
|
"kind": "cc0",
|
|
663
656
|
"spdx": "CC0-1.0",
|
|
664
657
|
"owner": "Kenney",
|
|
@@ -765,7 +758,6 @@
|
|
|
765
758
|
}
|
|
766
759
|
],
|
|
767
760
|
"license": {
|
|
768
|
-
"remix": "include",
|
|
769
761
|
"kind": "cc0",
|
|
770
762
|
"spdx": "CC0-1.0",
|
|
771
763
|
"owner": "Kenney",
|
|
@@ -870,7 +862,6 @@
|
|
|
870
862
|
}
|
|
871
863
|
],
|
|
872
864
|
"license": {
|
|
873
|
-
"remix": "include",
|
|
874
865
|
"kind": "cc0",
|
|
875
866
|
"spdx": "CC0-1.0",
|
|
876
867
|
"owner": "Kenney",
|
|
@@ -962,7 +953,6 @@
|
|
|
962
953
|
}
|
|
963
954
|
],
|
|
964
955
|
"license": {
|
|
965
|
-
"remix": "include",
|
|
966
956
|
"kind": "cc0",
|
|
967
957
|
"spdx": "CC0-1.0",
|
|
968
958
|
"owner": "Kenney",
|
|
@@ -1054,7 +1044,6 @@
|
|
|
1054
1044
|
}
|
|
1055
1045
|
],
|
|
1056
1046
|
"license": {
|
|
1057
|
-
"remix": "include",
|
|
1058
1047
|
"kind": "cc0",
|
|
1059
1048
|
"spdx": "CC0-1.0",
|
|
1060
1049
|
"owner": "Kenney",
|
|
@@ -1144,7 +1133,6 @@
|
|
|
1144
1133
|
}
|
|
1145
1134
|
],
|
|
1146
1135
|
"license": {
|
|
1147
|
-
"remix": "include",
|
|
1148
1136
|
"kind": "cc0",
|
|
1149
1137
|
"spdx": "CC0-1.0",
|
|
1150
1138
|
"owner": "Kenney",
|
|
@@ -1236,7 +1224,6 @@
|
|
|
1236
1224
|
}
|
|
1237
1225
|
],
|
|
1238
1226
|
"license": {
|
|
1239
|
-
"remix": "include",
|
|
1240
1227
|
"kind": "cc0",
|
|
1241
1228
|
"spdx": "CC0-1.0",
|
|
1242
1229
|
"owner": "Kenney",
|
|
@@ -1328,7 +1315,6 @@
|
|
|
1328
1315
|
}
|
|
1329
1316
|
],
|
|
1330
1317
|
"license": {
|
|
1331
|
-
"remix": "include",
|
|
1332
1318
|
"kind": "cc0",
|
|
1333
1319
|
"spdx": "CC0-1.0",
|
|
1334
1320
|
"owner": "Kenney",
|
|
@@ -1420,7 +1406,6 @@
|
|
|
1420
1406
|
}
|
|
1421
1407
|
],
|
|
1422
1408
|
"license": {
|
|
1423
|
-
"remix": "include",
|
|
1424
1409
|
"kind": "cc0",
|
|
1425
1410
|
"spdx": "CC0-1.0",
|
|
1426
1411
|
"owner": "Kenney",
|
|
@@ -1512,7 +1497,6 @@
|
|
|
1512
1497
|
}
|
|
1513
1498
|
],
|
|
1514
1499
|
"license": {
|
|
1515
|
-
"remix": "include",
|
|
1516
1500
|
"kind": "cc0",
|
|
1517
1501
|
"spdx": "CC0-1.0",
|
|
1518
1502
|
"owner": "Kenney",
|
|
@@ -1605,7 +1589,6 @@
|
|
|
1605
1589
|
}
|
|
1606
1590
|
],
|
|
1607
1591
|
"license": {
|
|
1608
|
-
"remix": "include",
|
|
1609
1592
|
"kind": "cc0",
|
|
1610
1593
|
"spdx": "CC0-1.0",
|
|
1611
1594
|
"owner": "Kenney",
|
|
@@ -1696,7 +1679,6 @@
|
|
|
1696
1679
|
}
|
|
1697
1680
|
],
|
|
1698
1681
|
"license": {
|
|
1699
|
-
"remix": "include",
|
|
1700
1682
|
"kind": "cc0",
|
|
1701
1683
|
"spdx": "CC0-1.0",
|
|
1702
1684
|
"owner": "Kenney",
|
|
@@ -1788,7 +1770,6 @@
|
|
|
1788
1770
|
}
|
|
1789
1771
|
],
|
|
1790
1772
|
"license": {
|
|
1791
|
-
"remix": "include",
|
|
1792
1773
|
"kind": "cc0",
|
|
1793
1774
|
"spdx": "CC0-1.0",
|
|
1794
1775
|
"owner": "Kenney",
|
|
@@ -1880,7 +1861,6 @@
|
|
|
1880
1861
|
}
|
|
1881
1862
|
],
|
|
1882
1863
|
"license": {
|
|
1883
|
-
"remix": "include",
|
|
1884
1864
|
"kind": "cc0",
|
|
1885
1865
|
"spdx": "CC0-1.0",
|
|
1886
1866
|
"owner": "Kenney",
|
|
@@ -1973,7 +1953,6 @@
|
|
|
1973
1953
|
}
|
|
1974
1954
|
],
|
|
1975
1955
|
"license": {
|
|
1976
|
-
"remix": "include",
|
|
1977
1956
|
"kind": "cc0",
|
|
1978
1957
|
"spdx": "CC0-1.0",
|
|
1979
1958
|
"owner": "Kenney",
|
|
@@ -2066,7 +2045,6 @@
|
|
|
2066
2045
|
}
|
|
2067
2046
|
],
|
|
2068
2047
|
"license": {
|
|
2069
|
-
"remix": "include",
|
|
2070
2048
|
"kind": "cc0",
|
|
2071
2049
|
"spdx": "CC0-1.0",
|
|
2072
2050
|
"owner": "Kenney",
|
|
@@ -2158,7 +2136,6 @@
|
|
|
2158
2136
|
}
|
|
2159
2137
|
],
|
|
2160
2138
|
"license": {
|
|
2161
|
-
"remix": "include",
|
|
2162
2139
|
"kind": "cc0",
|
|
2163
2140
|
"spdx": "CC0-1.0",
|
|
2164
2141
|
"owner": "Kenney",
|
|
@@ -2250,7 +2227,6 @@
|
|
|
2250
2227
|
}
|
|
2251
2228
|
],
|
|
2252
2229
|
"license": {
|
|
2253
|
-
"remix": "include",
|
|
2254
2230
|
"kind": "cc0",
|
|
2255
2231
|
"spdx": "CC0-1.0",
|
|
2256
2232
|
"owner": "Kenney",
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>Gem Rush 3D</title>
|
|
7
7
|
<link rel="icon" href="data:,">
|
|
8
8
|
<style>
|
|
9
|
-
html, body { margin: 0; height: 100%; background: #cfe8f5; overflow: hidden; overscroll-behavior: none; -webkit-user-select: none; user-select: none; }
|
|
9
|
+
html, body { margin: 0; height: 100%; background: #cfe8f5; overflow: hidden; overscroll-behavior: none; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
|
|
10
10
|
canvas { position: fixed; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }
|
|
11
11
|
/* The HUD is drawn over the world and never takes a touch: every touch reaches the world's canvas. */
|
|
12
12
|
#hud { pointer-events: none; }
|
|
@@ -23,6 +23,13 @@
|
|
|
23
23
|
* byte). A model that is refused or not there is drawn as a stand-in in the same colours (see "models" below): a
|
|
24
24
|
* round never waits on, or breaks for, a model.
|
|
25
25
|
*
|
|
26
|
+
* HEADINGS, AND THERE ARE TWO: a body's `yaw` is `Math.atan2(dx, dy)` in the game's own x and y, so yaw 0 faces +y
|
|
27
|
+
* (three.js's +z, the way the models are built) and it goes straight into `rotation.y`. That is also the yaw
|
|
28
|
+
* `@homie-rocks/camera` means (0 faces +Z, positive turns toward +X, radians), so a follow or chase camera from that
|
|
29
|
+
* package takes a body's `yaw` as it stands. The knock and aim angles (`ang`, `base`) are the OTHER kind,
|
|
30
|
+
* `Math.atan2(dy, dx)`: 0 faces +x. Never hand one of those to a camera or to `rotation.y` without converting it:
|
|
31
|
+
* `headingFrom({ zero: '+x', toward: '+z' })` from `@homie-rocks/camera/heading.js` is the adapter.
|
|
32
|
+
*
|
|
26
33
|
* PHONE BUDGETS: under 100 draw calls and 150k triangles a frame (the `drawCalls` and `triangles` probes read
|
|
27
34
|
* renderer.info), the pixel ratio at most 1.5 on a phone and 2 on a computer, and no shadow map on a phone: a soft
|
|
28
35
|
* disc under each body, gem, tree and rock (a computer draws the sun's real shadows). Repeated things (gems, trees, flowers, the fence, the discs) are one
|
|
@@ -42,7 +49,7 @@ import {
|
|
|
42
49
|
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
43
50
|
// The one model loader every studio game uses: checks each file, decodes meshopt and WebP, copies for placing.
|
|
44
51
|
import { createModels, instancedCopies, placeCopy, repaint, stylize, type Copies } from '@homie-rocks/studio/assets';
|
|
45
|
-
import { createNetplay, Roster, q, lerp, capMove, PALETTE, AI_MARK, type RoleChange, type RoundInfo, type RoundResult, type Skill, type Slot, type Snapshot } from '@homie-rocks/studio/netplay';
|
|
52
|
+
import { createNetplay, guardGestures, Roster, q, lerp, capMove, PALETTE, AI_MARK, type Peer, type RoleChange, type RoundInfo, type RoundResult, type Skill, type Slot, type Snapshot } from '@homie-rocks/studio/netplay';
|
|
46
53
|
// The port toolkit: its probe (what `homie-studio port check` and `perf` read, and sandbox + audio shims), and name
|
|
47
54
|
// labels that never pile up (port/view.ts).
|
|
48
55
|
import { createBubbles, createLabels, exposePort, paintBubbles, type BubbleIn, type BubbleOut, type LabelIn, type LabelOut } from '@homie-rocks/studio/port';
|
|
@@ -110,7 +117,7 @@ interface Body extends Knock { slot: number; seat: number | null; name: string;
|
|
|
110
117
|
interface Gem { id: number; x: number; y: number }
|
|
111
118
|
/** Slow state, on the keyed state channel (net.state('zone', ...)), not in the 20 Hz snapshot. */
|
|
112
119
|
interface Zone { n: number; x: number; y: number; r: number; until: number }
|
|
113
|
-
interface Ckpt { round: RoundInfo; bodies: Body[]; gems: Gem[]; roster: Slot[]; tick: number; gemSeq: number }
|
|
120
|
+
interface Ckpt { round: RoundInfo; bodies: Body[]; gems: Gem[]; roster: Slot[]; tick: number; gemSeq: number; occ?: [number, number][] }
|
|
114
121
|
|
|
115
122
|
/* --------------------------------------------------------------- the net */
|
|
116
123
|
/**
|
|
@@ -121,6 +128,9 @@ interface Ckpt { round: RoundInfo; bodies: Body[]; gems: Gem[]; roster: Slot[];
|
|
|
121
128
|
const MOVEMENT: 'owner' | 'host' = (() => { try { return new URLSearchParams(location.search).get('movement') === 'host' ? 'host' : 'owner'; } catch { return 'owner'; } })();
|
|
122
129
|
// caps: its bots read the dial ('skill'), and its Roster takes an AI's slot for it ('agents': the join passes p.agent).
|
|
123
130
|
const net = createNetplay<Snap, Avatar, Ckpt>({ game: 'gem-rush-3d', maxPlayers: MAX_SLOTS, movement: MOVEMENT, snapshotHz: 20, inputHz: 20, checkpointMs: 1000, caps: ['skill', 'agents'], checkpoint: () => checkpoint() });
|
|
131
|
+
// A touch game guards its own page (NETPLAY.md section 24): a long press on the canvas never selects text or raises
|
|
132
|
+
// the copy/paste callout on a phone, and a touch on it never pans or zooms the page.
|
|
133
|
+
guardGestures({ touch: 'canvas' });
|
|
124
134
|
/** The Roster keeps the server's AI seats (revision 6): the policy is read whenever it fills. */
|
|
125
135
|
const policy = () => net.policy;
|
|
126
136
|
|
|
@@ -196,9 +206,12 @@ function newZone(n: number): Zone {
|
|
|
196
206
|
}
|
|
197
207
|
function setZone(z: Zone): void { zone = z; net.state('zone', z); }
|
|
198
208
|
|
|
199
|
-
function startRound(n: number): void {
|
|
209
|
+
function startRound(n: number, rollover = false): void {
|
|
200
210
|
const now = net.now();
|
|
201
211
|
roster.trim();
|
|
212
|
+
// The next round of a running room: the trim is what makes room (the seats a server no longer keeps for AI go
|
|
213
|
+
// here), so whoever was seated with no body is given one now, before the bodies are placed.
|
|
214
|
+
if (rollover && !net.offline) seatWaiting();
|
|
202
215
|
syncBodiesFromRoster();
|
|
203
216
|
let i = 0;
|
|
204
217
|
for (const b of [...bodies.values()].sort((a, c) => a.slot - c.slot)) {
|
|
@@ -240,7 +253,9 @@ function becomeHost(e: RoleChange<Snap, Ckpt>): void {
|
|
|
240
253
|
startRound((e.round?.n ?? 0) + 1);
|
|
241
254
|
}
|
|
242
255
|
// Whoever is connected now is who plays: seats that left during the gap become bots.
|
|
243
|
-
const peers = net.offline ? [{ seat: 0, name: 'You' }] : [...net.peers.values()].filter((p) => p.seat !== null).map((p) => ({ seat: p.seat, name: p.name, agent: p.agent ?? null }));
|
|
256
|
+
const peers = net.offline ? [{ seat: 0, name: 'You' }] : [...net.peers.values()].filter((p) => p.seat !== null).map((p) => ({ seat: p.seat, name: p.name, agent: p.agent ?? null, occ: p.occ ?? null }));
|
|
257
|
+
// `occ` (NETPLAY.md section 25): which stay in its seat each peer's is, so a seat number that changed hands while
|
|
258
|
+
// nobody was hosting is claimed afresh instead of inheriting the last player's body in silence.
|
|
244
259
|
const { claimed } = roster.reconcile(peers);
|
|
245
260
|
syncBodiesFromRoster();
|
|
246
261
|
for (const s of claimed) { const b = bodies.get(s.slot); if (b && b.seat !== mySeat()) hostMoved(b); }
|
|
@@ -257,7 +272,7 @@ function becomeHost(e: RoleChange<Snap, Ckpt>): void {
|
|
|
257
272
|
function restore(e: RoleChange<Snap, Ckpt>): void {
|
|
258
273
|
const ck = e.ckpt?.d ?? null;
|
|
259
274
|
if (ck) {
|
|
260
|
-
roster = Roster.from(ck.roster, { min: MIN_SLOTS, max: MAX_SLOTS, botName, policy });
|
|
275
|
+
roster = Roster.from(ck.roster, { min: MIN_SLOTS, max: MAX_SLOTS, botName, policy }, ck.occ ?? null);
|
|
261
276
|
bodies = new Map(ck.bodies.map((b) => [b.slot, { ...b }]));
|
|
262
277
|
gems = ck.gems.map((g) => ({ ...g }));
|
|
263
278
|
gemSeq = ck.gemSeq;
|
|
@@ -298,6 +313,8 @@ function checkpoint(): Ckpt {
|
|
|
298
313
|
bodies: [...bodies.values()].map((b) => ({ ...b })),
|
|
299
314
|
gems: gems.map((g) => ({ ...g })),
|
|
300
315
|
roster: roster.toJSON(),
|
|
316
|
+
// Whose stay each body is, beside the roster: how the next host tells a player who came back from a new one.
|
|
317
|
+
occ: roster.occupants(),
|
|
301
318
|
tick,
|
|
302
319
|
gemSeq,
|
|
303
320
|
};
|
|
@@ -307,15 +324,30 @@ net.on('role', (e) => {
|
|
|
307
324
|
if (e.role === 'host') becomeHost(e);
|
|
308
325
|
else { hosting = false; }
|
|
309
326
|
});
|
|
310
|
-
|
|
311
|
-
|
|
327
|
+
/** Host: a body for somebody the relay seated. False when every body is somebody's (they wait: see seatWaiting). */
|
|
328
|
+
function giveBody(p: Peer): boolean {
|
|
329
|
+
if (p.seat === null) return false;
|
|
312
330
|
// An AI takes a seat kept for AI, a person never does (revision 6: the Roster needs p.agent for that).
|
|
313
|
-
const c = roster.claim(p.seat, p.name, p.agent ? { role: p.agent.role, hands: p.agent.hands } : null);
|
|
314
|
-
if (!c) return;
|
|
331
|
+
const c = roster.claim(p.seat, p.name, p.agent ? { role: p.agent.role, hands: p.agent.hands } : null, p.occ ?? null);
|
|
332
|
+
if (!c) return false;
|
|
315
333
|
syncBodiesFromRoster();
|
|
316
334
|
const b = bodies.get(c.slot.slot);
|
|
317
335
|
// The arriving human takes over the bot's body where it stands, score and all (reset = "adopt this position").
|
|
318
336
|
if (b) { b.vx = 0; b.vy = 0; b.kvx = 0; b.kvy = 0; b.knockUntil = 0; hostMoved(b); }
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* SEAT WHOEVER IS WAITING (NETPLAY.md section 28). The relay seats a person; this host gives them a body. A claim that
|
|
341
|
+
* found every body taken (a server's AI seats were still kept, say) used to be tried once: that player watched for the
|
|
342
|
+
* rest of the visit, online, with nothing said. It is tried again whenever a body frees up and at every round start.
|
|
343
|
+
*/
|
|
344
|
+
function seatWaiting(): boolean {
|
|
345
|
+
let any = false;
|
|
346
|
+
for (const p of net.peers.values()) if (p.seat !== null && !roster.bySeat(p.seat) && giveBody(p)) any = true;
|
|
347
|
+
return any;
|
|
348
|
+
}
|
|
349
|
+
net.on('join', (p) => {
|
|
350
|
+
if (!hosting || !giveBody(p)) return;
|
|
319
351
|
publishRoster();
|
|
320
352
|
net.snapshot(buildSnap(), tick, true);
|
|
321
353
|
});
|
|
@@ -323,7 +355,10 @@ net.on('leave', (p) => {
|
|
|
323
355
|
if (!hosting || p.seat === null) return;
|
|
324
356
|
roster.release(p.seat); // their body stays, driven by a bot
|
|
325
357
|
syncBodiesFromRoster();
|
|
358
|
+
// A body just went to a bot: somebody seated with none takes it now.
|
|
359
|
+
const seated = seatWaiting();
|
|
326
360
|
publishRoster();
|
|
361
|
+
if (seated) net.snapshot(buildSnap(), tick, true);
|
|
327
362
|
});
|
|
328
363
|
// The server's policy changed: its AI seats come (or go between rounds) at once.
|
|
329
364
|
net.on('policy', () => { if (!hosting) return; roster.fill(); syncBodiesFromRoster(); publishRoster(); });
|
|
@@ -610,7 +645,7 @@ function stepHost(dt: number): void {
|
|
|
610
645
|
}
|
|
611
646
|
}
|
|
612
647
|
if (now >= round.endsAt) endRound();
|
|
613
|
-
} else if (round && round.phase === 'over' && now >= round.endsAt) startRound(round.n + 1);
|
|
648
|
+
} else if (round && round.phase === 'over' && now >= round.endsAt) startRound(round.n + 1, true);
|
|
614
649
|
if (net.snapshotDue()) net.snapshot(buildSnap(), tick);
|
|
615
650
|
}
|
|
616
651
|
|
|
@@ -2014,7 +2049,8 @@ function hud(cw: number, ch: number, phone: boolean, list: { slot: number; seat:
|
|
|
2014
2049
|
ctx.fillText(`${TOGETHER ? '' : `${row.place}. `}${mine && !net.watching ? 'You' : label(row.name, row.bot)}${mine && net.watching ? ' ◂' : ''} — ${row.score}`, cw / 2, ry + 1);
|
|
2015
2050
|
});
|
|
2016
2051
|
}
|
|
2017
|
-
|
|
2052
|
+
// Only a browser that WAS in its room is reconnecting; one still joining, or stopped for good, is not (section 22).
|
|
2053
|
+
if (net.link === 'reconnecting' && net.role !== 'host') {
|
|
2018
2054
|
ctx.textAlign = 'center'; ctx.font = `700 15px ${FONT_BODY}`;
|
|
2019
2055
|
const text = 'Reconnecting…'; const tw = ctx.measureText(text).width;
|
|
2020
2056
|
chip(cw / 2 - tw / 2 - 12, ch - pad - 24, tw + 24, 26);
|
|
@@ -2095,6 +2131,9 @@ exposePort(net, {
|
|
|
2095
2131
|
self: () => (me.has && mySeat() !== null ? { x: me.x, y: me.y } : null),
|
|
2096
2132
|
size: R_AV,
|
|
2097
2133
|
score: () => { const seat = mySeat(); const b = hosting ? [...bodies.values()].find((x) => x.seat === seat) : [...drawn.values()].find((x) => x.seat === seat); return b ? b.score : null; },
|
|
2134
|
+
// The renderer's own counters, by the names `homie-studio perf` and the playtest read on the port probe (measured
|
|
2135
|
+
// scene cost while playing; port/probe.ts PortExtra). Nobody dies in this game, so there is no `alive` to say.
|
|
2136
|
+
extra: { drawCalls: () => renderer.info.render.calls, triangles: () => renderer.info.render.triangles },
|
|
2098
2137
|
});
|
|
2099
2138
|
|
|
2100
2139
|
void net.ready.then(() => {
|
|
@@ -15,7 +15,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
15
15
|
- **What:** character (Players/Barbarian): `public/models/barbarian.glb`
|
|
16
16
|
- **From:** from the Homie starter library: KayKit Adventurers, barbarian (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Adventures-1.0); library
|
|
17
17
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
18
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
19
18
|
- **Notes:** From the Homie starter library (kaykit-adventurers); the pack's own licence text: licenses/kaykit-adventurers.txt. `game new` fetches the file, makes the character phone-sized and bakes its clips; the repository holds no models.
|
|
20
19
|
|
|
21
20
|
### barrel
|
|
@@ -23,7 +22,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
23
22
|
- **What:** prop (Places/Barrel): `public/models/barrel.glb`
|
|
24
23
|
- **From:** from the Homie starter library: KayKit Medieval Hexagon, barrel (https://github.com/KayKit-Game-Assets/KayKit-Medieval-Hexagon-Pack-1.0); library
|
|
25
24
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
26
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
27
25
|
- **Notes:** From the Homie starter library (kaykit-medieval-hexagon); the pack's own licence text: licenses/kaykit-medieval-hexagon.txt. `game new` fetches the file; the repository holds no models.
|
|
28
26
|
|
|
29
27
|
### chest
|
|
@@ -31,7 +29,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
31
29
|
- **What:** prop (Places/Treasure Chest): `public/models/chest.glb`
|
|
32
30
|
- **From:** from the Homie starter library: KayKit Dungeon Remastered, chest-gold (https://github.com/KayKit-Game-Assets/KayKit-Dungeon-Remastered-1.0); library
|
|
33
31
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
34
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
35
32
|
- **Notes:** From the Homie starter library (kaykit-dungeon); the pack's own licence text: licenses/kaykit-dungeon.txt. `game new` fetches the file; the repository holds no models.
|
|
36
33
|
|
|
37
34
|
### coin
|
|
@@ -39,7 +36,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
39
36
|
- **What:** prop (Items/Coin): `public/models/coin.glb`
|
|
40
37
|
- **From:** from the Homie starter library: KayKit Dungeon Remastered, coin (https://github.com/KayKit-Game-Assets/KayKit-Dungeon-Remastered-1.0); library
|
|
41
38
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
42
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
43
39
|
- **Notes:** From the Homie starter library (kaykit-dungeon); the pack's own licence text: licenses/kaykit-dungeon.txt. `game new` fetches the file; the repository holds no models.
|
|
44
40
|
|
|
45
41
|
### crate
|
|
@@ -47,7 +43,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
47
43
|
- **What:** prop (Places/Crate): `public/models/crate.glb`
|
|
48
44
|
- **From:** from the Homie starter library: KayKit Medieval Hexagon, crate-a-big (https://github.com/KayKit-Game-Assets/KayKit-Medieval-Hexagon-Pack-1.0); library
|
|
49
45
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
50
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
51
46
|
- **Notes:** From the Homie starter library (kaykit-medieval-hexagon); the pack's own licence text: licenses/kaykit-medieval-hexagon.txt. `game new` fetches the file; the repository holds no models.
|
|
52
47
|
|
|
53
48
|
### grove
|
|
@@ -55,7 +50,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
55
50
|
- **What:** prop (Places/Grove): `public/models/grove.glb`
|
|
56
51
|
- **From:** from the Homie starter library: KayKit Medieval Hexagon, trees-a-medium (https://github.com/KayKit-Game-Assets/KayKit-Medieval-Hexagon-Pack-1.0); library
|
|
57
52
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
58
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
59
53
|
- **Notes:** From the Homie starter library (kaykit-medieval-hexagon); the pack's own licence text: licenses/kaykit-medieval-hexagon.txt. `game new` fetches the file; the repository holds no models.
|
|
60
54
|
|
|
61
55
|
### knight
|
|
@@ -63,7 +57,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
63
57
|
- **What:** character (Players/Knight): `public/models/knight.glb`
|
|
64
58
|
- **From:** from the Homie starter library: KayKit Adventurers, knight (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Adventures-1.0); library
|
|
65
59
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
66
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
67
60
|
- **Notes:** From the Homie starter library (kaykit-adventurers); the pack's own licence text: licenses/kaykit-adventurers.txt. `game new` fetches the file, makes the character phone-sized and bakes its clips; the repository holds no models.
|
|
68
61
|
|
|
69
62
|
### mage
|
|
@@ -71,7 +64,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
71
64
|
- **What:** character (Players/Mage): `public/models/mage.glb`
|
|
72
65
|
- **From:** from the Homie starter library: KayKit Adventurers, mage (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Adventures-1.0); library
|
|
73
66
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
74
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
75
67
|
- **Notes:** From the Homie starter library (kaykit-adventurers); the pack's own licence text: licenses/kaykit-adventurers.txt. `game new` fetches the file, makes the character phone-sized and bakes its clips; the repository holds no models.
|
|
76
68
|
|
|
77
69
|
### pine
|
|
@@ -79,7 +71,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
79
71
|
- **What:** prop (Places/Pine): `public/models/pine.glb`
|
|
80
72
|
- **From:** from the Homie starter library: KayKit Medieval Hexagon, tree-single-a (https://github.com/KayKit-Game-Assets/KayKit-Medieval-Hexagon-Pack-1.0); library
|
|
81
73
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
82
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
83
74
|
- **Notes:** From the Homie starter library (kaykit-medieval-hexagon); the pack's own licence text: licenses/kaykit-medieval-hexagon.txt. `game new` fetches the file; the repository holds no models.
|
|
84
75
|
|
|
85
76
|
### pine-round
|
|
@@ -87,7 +78,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
87
78
|
- **What:** prop (Places/Round Pine): `public/models/pine-round.glb`
|
|
88
79
|
- **From:** from the Homie starter library: KayKit Medieval Hexagon, tree-single-b (https://github.com/KayKit-Game-Assets/KayKit-Medieval-Hexagon-Pack-1.0); library
|
|
89
80
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
90
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
91
81
|
- **Notes:** From the Homie starter library (kaykit-medieval-hexagon); the pack's own licence text: licenses/kaykit-medieval-hexagon.txt. `game new` fetches the file; the repository holds no models.
|
|
92
82
|
|
|
93
83
|
### rock
|
|
@@ -95,7 +85,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
95
85
|
- **What:** prop (Places/Rock): `public/models/rock.glb`
|
|
96
86
|
- **From:** from the Homie starter library: KayKit Medieval Hexagon, rock-single-e (https://github.com/KayKit-Game-Assets/KayKit-Medieval-Hexagon-Pack-1.0); library
|
|
97
87
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
98
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
99
88
|
- **Notes:** From the Homie starter library (kaykit-medieval-hexagon); the pack's own licence text: licenses/kaykit-medieval-hexagon.txt. `game new` fetches the file; the repository holds no models.
|
|
100
89
|
|
|
101
90
|
### rocks
|
|
@@ -103,7 +92,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
103
92
|
- **What:** prop (Places/Rocks): `public/models/rocks.glb`
|
|
104
93
|
- **From:** from the Homie starter library: KayKit Medieval Hexagon, rock-single-c (https://github.com/KayKit-Game-Assets/KayKit-Medieval-Hexagon-Pack-1.0); library
|
|
105
94
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
106
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
107
95
|
- **Notes:** From the Homie starter library (kaykit-medieval-hexagon); the pack's own licence text: licenses/kaykit-medieval-hexagon.txt. `game new` fetches the file; the repository holds no models.
|
|
108
96
|
|
|
109
97
|
### rogue
|
|
@@ -111,7 +99,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
111
99
|
- **What:** character (Players/Rogue): `public/models/rogue.glb`
|
|
112
100
|
- **From:** from the Homie starter library: KayKit Adventurers, rogue (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Adventures-1.0); library
|
|
113
101
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
114
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
115
102
|
- **Notes:** From the Homie starter library (kaykit-adventurers); the pack's own licence text: licenses/kaykit-adventurers.txt. `game new` fetches the file, makes the character phone-sized and bakes its clips; the repository holds no models.
|
|
116
103
|
|
|
117
104
|
### rogue-hooded
|
|
@@ -119,7 +106,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
119
106
|
- **What:** character (Players/Hooded Rogue): `public/models/rogue-hooded.glb`
|
|
120
107
|
- **From:** from the Homie starter library: KayKit Adventurers, rogue-hooded (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Adventures-1.0); library
|
|
121
108
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
122
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
123
109
|
- **Notes:** From the Homie starter library (kaykit-adventurers); the pack's own licence text: licenses/kaykit-adventurers.txt. `game new` fetches the file, makes the character phone-sized and bakes its clips; the repository holds no models.
|
|
124
110
|
|
|
125
111
|
### skeleton-mage
|
|
@@ -127,7 +113,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
127
113
|
- **What:** creature (Creatures/Skeleton Mage): `public/models/skeleton-mage.glb`
|
|
128
114
|
- **From:** from the Homie starter library: KayKit Skeletons, skeleton-mage (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Skeletons-1.0); library
|
|
129
115
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
130
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
131
116
|
- **Notes:** From the Homie starter library (kaykit-skeletons); the pack's own licence text: licenses/kaykit-skeletons.txt. `game new` fetches the file, makes the character phone-sized and bakes its clips; the repository holds no models.
|
|
132
117
|
|
|
133
118
|
### skeleton-minion
|
|
@@ -135,7 +120,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
135
120
|
- **What:** creature (Creatures/Skeleton Minion): `public/models/skeleton-minion.glb`
|
|
136
121
|
- **From:** from the Homie starter library: KayKit Skeletons, skeleton-minion (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Skeletons-1.0); library
|
|
137
122
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
138
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
139
123
|
- **Notes:** From the Homie starter library (kaykit-skeletons); the pack's own licence text: licenses/kaykit-skeletons.txt. `game new` fetches the file, makes the character phone-sized and bakes its clips; the repository holds no models.
|
|
140
124
|
|
|
141
125
|
### skeleton-rogue
|
|
@@ -143,7 +127,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
143
127
|
- **What:** creature (Creatures/Skeleton Rogue): `public/models/skeleton-rogue.glb`
|
|
144
128
|
- **From:** from the Homie starter library: KayKit Skeletons, skeleton-rogue (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Skeletons-1.0); library
|
|
145
129
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
146
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
147
130
|
- **Notes:** From the Homie starter library (kaykit-skeletons); the pack's own licence text: licenses/kaykit-skeletons.txt. `game new` fetches the file, makes the character phone-sized and bakes its clips; the repository holds no models.
|
|
148
131
|
|
|
149
132
|
### skeleton-warrior
|
|
@@ -151,7 +134,6 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
151
134
|
- **What:** creature (Creatures/Skeleton Warrior): `public/models/skeleton-warrior.glb`
|
|
152
135
|
- **From:** from the Homie starter library: KayKit Skeletons, skeleton-warrior (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Skeletons-1.0); library
|
|
153
136
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
154
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
155
137
|
- **Notes:** From the Homie starter library (kaykit-skeletons); the pack's own licence text: licenses/kaykit-skeletons.txt. `game new` fetches the file, makes the character phone-sized and bakes its clips; the repository holds no models.
|
|
156
138
|
|
|
157
139
|
### torch
|
|
@@ -159,5 +141,4 @@ Read on the dates shown. Terms change: read the live page again before publishin
|
|
|
159
141
|
- **What:** prop (Places/Torch): `public/models/torch.glb`
|
|
160
142
|
- **From:** from the Homie starter library: KayKit Dungeon Remastered, torch-lit (https://github.com/KayKit-Game-Assets/KayKit-Dungeon-Remastered-1.0); library
|
|
161
143
|
- **Licence:** CC0 1.0 (public domain) (https://creativecommons.org/publicdomain/zero/1.0/); owner: KayKit
|
|
162
|
-
- **A remix:** a remix gets this file (fetched from this studio's site, checked by SHA-256)
|
|
163
144
|
- **Notes:** From the Homie starter library (kaykit-dungeon); the pack's own licence text: licenses/kaykit-dungeon.txt. `game new` fetches the file; the repository holds no models.
|
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
}
|
|
30
30
|
],
|
|
31
31
|
"license": {
|
|
32
|
-
"remix": "include",
|
|
33
32
|
"kind": "cc0",
|
|
34
33
|
"spdx": "CC0-1.0",
|
|
35
34
|
"owner": "KayKit",
|
|
@@ -118,7 +117,6 @@
|
|
|
118
117
|
}
|
|
119
118
|
],
|
|
120
119
|
"license": {
|
|
121
|
-
"remix": "include",
|
|
122
120
|
"kind": "cc0",
|
|
123
121
|
"spdx": "CC0-1.0",
|
|
124
122
|
"owner": "KayKit",
|
|
@@ -186,7 +184,6 @@
|
|
|
186
184
|
}
|
|
187
185
|
],
|
|
188
186
|
"license": {
|
|
189
|
-
"remix": "include",
|
|
190
187
|
"kind": "cc0",
|
|
191
188
|
"spdx": "CC0-1.0",
|
|
192
189
|
"owner": "KayKit",
|
|
@@ -254,7 +251,6 @@
|
|
|
254
251
|
}
|
|
255
252
|
],
|
|
256
253
|
"license": {
|
|
257
|
-
"remix": "include",
|
|
258
254
|
"kind": "cc0",
|
|
259
255
|
"spdx": "CC0-1.0",
|
|
260
256
|
"owner": "KayKit",
|
|
@@ -322,7 +318,6 @@
|
|
|
322
318
|
}
|
|
323
319
|
],
|
|
324
320
|
"license": {
|
|
325
|
-
"remix": "include",
|
|
326
321
|
"kind": "cc0",
|
|
327
322
|
"spdx": "CC0-1.0",
|
|
328
323
|
"owner": "KayKit",
|
|
@@ -390,7 +385,6 @@
|
|
|
390
385
|
}
|
|
391
386
|
],
|
|
392
387
|
"license": {
|
|
393
|
-
"remix": "include",
|
|
394
388
|
"kind": "cc0",
|
|
395
389
|
"spdx": "CC0-1.0",
|
|
396
390
|
"owner": "KayKit",
|
|
@@ -458,7 +452,6 @@
|
|
|
458
452
|
}
|
|
459
453
|
],
|
|
460
454
|
"license": {
|
|
461
|
-
"remix": "include",
|
|
462
455
|
"kind": "cc0",
|
|
463
456
|
"spdx": "CC0-1.0",
|
|
464
457
|
"owner": "KayKit",
|
|
@@ -547,7 +540,6 @@
|
|
|
547
540
|
}
|
|
548
541
|
],
|
|
549
542
|
"license": {
|
|
550
|
-
"remix": "include",
|
|
551
543
|
"kind": "cc0",
|
|
552
544
|
"spdx": "CC0-1.0",
|
|
553
545
|
"owner": "KayKit",
|
|
@@ -636,7 +628,6 @@
|
|
|
636
628
|
}
|
|
637
629
|
],
|
|
638
630
|
"license": {
|
|
639
|
-
"remix": "include",
|
|
640
631
|
"kind": "cc0",
|
|
641
632
|
"spdx": "CC0-1.0",
|
|
642
633
|
"owner": "KayKit",
|
|
@@ -704,7 +695,6 @@
|
|
|
704
695
|
}
|
|
705
696
|
],
|
|
706
697
|
"license": {
|
|
707
|
-
"remix": "include",
|
|
708
698
|
"kind": "cc0",
|
|
709
699
|
"spdx": "CC0-1.0",
|
|
710
700
|
"owner": "KayKit",
|
|
@@ -772,7 +762,6 @@
|
|
|
772
762
|
}
|
|
773
763
|
],
|
|
774
764
|
"license": {
|
|
775
|
-
"remix": "include",
|
|
776
765
|
"kind": "cc0",
|
|
777
766
|
"spdx": "CC0-1.0",
|
|
778
767
|
"owner": "KayKit",
|
|
@@ -840,7 +829,6 @@
|
|
|
840
829
|
}
|
|
841
830
|
],
|
|
842
831
|
"license": {
|
|
843
|
-
"remix": "include",
|
|
844
832
|
"kind": "cc0",
|
|
845
833
|
"spdx": "CC0-1.0",
|
|
846
834
|
"owner": "KayKit",
|
|
@@ -908,7 +896,6 @@
|
|
|
908
896
|
}
|
|
909
897
|
],
|
|
910
898
|
"license": {
|
|
911
|
-
"remix": "include",
|
|
912
899
|
"kind": "cc0",
|
|
913
900
|
"spdx": "CC0-1.0",
|
|
914
901
|
"owner": "KayKit",
|
|
@@ -996,7 +983,6 @@
|
|
|
996
983
|
}
|
|
997
984
|
],
|
|
998
985
|
"license": {
|
|
999
|
-
"remix": "include",
|
|
1000
986
|
"kind": "cc0",
|
|
1001
987
|
"spdx": "CC0-1.0",
|
|
1002
988
|
"owner": "KayKit",
|
|
@@ -1084,7 +1070,6 @@
|
|
|
1084
1070
|
}
|
|
1085
1071
|
],
|
|
1086
1072
|
"license": {
|
|
1087
|
-
"remix": "include",
|
|
1088
1073
|
"kind": "cc0",
|
|
1089
1074
|
"spdx": "CC0-1.0",
|
|
1090
1075
|
"owner": "KayKit",
|
|
@@ -1170,7 +1155,6 @@
|
|
|
1170
1155
|
}
|
|
1171
1156
|
],
|
|
1172
1157
|
"license": {
|
|
1173
|
-
"remix": "include",
|
|
1174
1158
|
"kind": "cc0",
|
|
1175
1159
|
"spdx": "CC0-1.0",
|
|
1176
1160
|
"owner": "KayKit",
|
|
@@ -1254,7 +1238,6 @@
|
|
|
1254
1238
|
}
|
|
1255
1239
|
],
|
|
1256
1240
|
"license": {
|
|
1257
|
-
"remix": "include",
|
|
1258
1241
|
"kind": "cc0",
|
|
1259
1242
|
"spdx": "CC0-1.0",
|
|
1260
1243
|
"owner": "KayKit",
|
|
@@ -1341,7 +1324,6 @@
|
|
|
1341
1324
|
}
|
|
1342
1325
|
],
|
|
1343
1326
|
"license": {
|
|
1344
|
-
"remix": "include",
|
|
1345
1327
|
"kind": "cc0",
|
|
1346
1328
|
"spdx": "CC0-1.0",
|
|
1347
1329
|
"owner": "KayKit",
|
|
@@ -1427,7 +1409,6 @@
|
|
|
1427
1409
|
}
|
|
1428
1410
|
],
|
|
1429
1411
|
"license": {
|
|
1430
|
-
"remix": "include",
|
|
1431
1412
|
"kind": "cc0",
|
|
1432
1413
|
"spdx": "CC0-1.0",
|
|
1433
1414
|
"owner": "KayKit",
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>Hero Rush 3D</title>
|
|
7
7
|
<link rel="icon" href="data:,">
|
|
8
8
|
<style>
|
|
9
|
-
html, body { margin: 0; height: 100%; background: #cfe8f5; overflow: hidden; overscroll-behavior: none; -webkit-user-select: none; user-select: none; }
|
|
9
|
+
html, body { margin: 0; height: 100%; background: #cfe8f5; overflow: hidden; overscroll-behavior: none; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
|
|
10
10
|
canvas { position: fixed; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }
|
|
11
11
|
/* The HUD is drawn over the world and never takes a touch: every touch reaches the world's canvas. */
|
|
12
12
|
#hud { pointer-events: none; }
|