@homie-rocks/studio 0.24.4 → 0.25.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/CHANGELOG.md +55 -1
- package/README.md +50 -3
- package/assets/animate.ts +521 -0
- package/assets/render-page.ts +77 -4
- package/bin/homie-studio.mjs +13 -4
- package/chat/CHAT.md +36 -5
- package/lib/art-cli.mjs +105 -5
- package/lib/art-tools.mjs +168 -1
- package/lib/asset-check.mjs +72 -5
- package/lib/build.mjs +3 -0
- package/lib/characters.mjs +380 -0
- package/lib/clips.mjs +417 -0
- package/lib/decisions.mjs +38 -8
- package/lib/mcp-tools.mjs +1 -1
- package/lib/mcp.mjs +2 -2
- package/lib/optimise.mjs +79 -3
- package/lib/render3d.mjs +2 -0
- package/lib/rig.mjs +431 -0
- package/lib/scaffold.mjs +17 -4
- package/lib/studio.mjs +18 -3
- package/lib/style-board.mjs +3 -1
- package/lib/template-history.json +78 -0
- package/mcp/ui/animation.js +56 -0
- package/mcp/ui/card.css +4 -0
- package/mcp/ui/cast.js +36 -2
- package/mcp/ui/lineup.js +7 -7
- package/netplay/NETPLAY.md +9 -5
- package/package.json +5 -1
- package/site/SITE.md +4 -0
- package/starters/hero-rush-3d/assets/RIGHTS.md +163 -0
- package/starters/hero-rush-3d/assets/manifest.json +1471 -0
- package/starters/hero-rush-3d/credits.json +40 -0
- package/starters/hero-rush-3d/game.json +11 -0
- package/starters/hero-rush-3d/index.html +20 -0
- package/starters/hero-rush-3d/lab.json +32 -0
- package/starters/hero-rush-3d/src/main.ts +2361 -0
- package/starters/hero-rush-3d/style.json +68 -0
- package/starters/hero-rush-3d/tunables.json +32 -0
- package/worker/chat-page.mjs +173 -28
- package/worker/chat.mjs +4 -1
- package/worker/version.mjs +1 -1
package/lib/style-board.mjs
CHANGED
|
@@ -170,7 +170,9 @@ export async function assetsLineup(root, id, { log = () => {} } = {}) {
|
|
|
170
170
|
// `inGame`: what the game's code does to it at runtime (drawn at another height, repainted from style.json): the
|
|
171
171
|
// lineup draws it the same way (the repaint as the board's re-tint, the nearest the game's own swap can be shown).
|
|
172
172
|
const scale = a.inGame?.heightM && a.measured?.heightM ? a.inGame.heightM / a.measured.heightM : null;
|
|
173
|
-
|
|
173
|
+
// A character stands in its idle pose from its skeleton's clip library (not its bind pose: arms out in a T).
|
|
174
|
+
const anims = a.rig?.anims && existsSync(join(root, 'games', id, a.rig.anims)) ? readFileSync(join(root, 'games', id, a.rig.anims)).toString('base64') : null;
|
|
175
|
+
models.push({ a, input: modelIn(a.id, readFileSync(abs), { label: a.card ? String(a.card).split('/').pop() : a.id, ...(scale ? { scale } : {}), ...(anims ? { anims, pose: 'idle', poseAt: 0.3 } : {}), ...(a.inGame?.tint ? { tint: lightColours({ sky: a.inGame.tint, ground: a.inGame.tint }, tokens.palette).sky } : a.inGame?.repaint ? { retint: true } : Number(a.inGame?.pull) > 0 ? { pull: Number(a.inGame.pull) } : {}) }), abs });
|
|
174
176
|
}
|
|
175
177
|
if (!models.length) return { ok: false, command: 'assets lineup', id, why: `games/${id} has no recorded models yet (assets add, or the models skill)` };
|
|
176
178
|
const dir = join(root, '.studio', 'art', id);
|
|
@@ -1156,6 +1156,84 @@
|
|
|
1156
1156
|
}
|
|
1157
1157
|
}
|
|
1158
1158
|
}
|
|
1159
|
+
},
|
|
1160
|
+
"0.24.5": {
|
|
1161
|
+
"files": {
|
|
1162
|
+
"CLAUDE.md": "ddf2b2a0376202f6",
|
|
1163
|
+
"README.md": "684b3cca8001673c",
|
|
1164
|
+
"HANDOFF.md": "ce7a8fd91c6bbee2",
|
|
1165
|
+
"games/README.md": "5ad32fe80c61f117",
|
|
1166
|
+
"music/README.md": "a3dc042dadd39df8",
|
|
1167
|
+
"videos/README.md": "16babc3437d5545b",
|
|
1168
|
+
"posts/README.md": "37841aae476bd540",
|
|
1169
|
+
"site/README.md": "ca131cd0472464fb",
|
|
1170
|
+
"site/src/worker.mjs": "ca3f1630f2420ad3"
|
|
1171
|
+
},
|
|
1172
|
+
"sections": {
|
|
1173
|
+
"AGENTS.md": {
|
|
1174
|
+
"(intro)": "214aa46eb3a895d5",
|
|
1175
|
+
"## Layout": "8baf49e4291e7e88",
|
|
1176
|
+
"## Commands (all through the pinned CLI in node_modules)": "d80ec56e4b4fc4c6",
|
|
1177
|
+
"## The site": "ab922bb6bde23293",
|
|
1178
|
+
"## Making games": "abf2f0d59341512d",
|
|
1179
|
+
"## The Game Codex and progress": "0738ef719cef3a4c",
|
|
1180
|
+
"## Art direction and models": "124772c374de7390",
|
|
1181
|
+
"## Running live games (the back office)": "4aa5f513a7cd2c3b",
|
|
1182
|
+
"## Servers and AI seats": "98d08705087a33ec",
|
|
1183
|
+
"## Selling things (the shop)": "b04b0a2b25f524f2",
|
|
1184
|
+
"## Continuing a build from the Claude app": "0d68081e924ca419",
|
|
1185
|
+
"## Rules": "7e8458adc1b81ece",
|
|
1186
|
+
"## Beta": "9d02638207a26e73"
|
|
1187
|
+
}
|
|
1188
|
+
},
|
|
1189
|
+
"named": {
|
|
1190
|
+
"Homie Arcade": {
|
|
1191
|
+
"sections": {
|
|
1192
|
+
"AGENTS.md": {
|
|
1193
|
+
"## Commands (all through the pinned CLI in node_modules)": "b35df2c19cd4b534"
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
},
|
|
1199
|
+
"0.25.0": {
|
|
1200
|
+
"files": {
|
|
1201
|
+
"CLAUDE.md": "ddf2b2a0376202f6",
|
|
1202
|
+
"README.md": "684b3cca8001673c",
|
|
1203
|
+
"HANDOFF.md": "ce7a8fd91c6bbee2",
|
|
1204
|
+
"games/README.md": "5ad32fe80c61f117",
|
|
1205
|
+
"music/README.md": "a3dc042dadd39df8",
|
|
1206
|
+
"videos/README.md": "16babc3437d5545b",
|
|
1207
|
+
"posts/README.md": "37841aae476bd540",
|
|
1208
|
+
"site/README.md": "ca131cd0472464fb",
|
|
1209
|
+
"site/src/worker.mjs": "ca3f1630f2420ad3"
|
|
1210
|
+
},
|
|
1211
|
+
"sections": {
|
|
1212
|
+
"AGENTS.md": {
|
|
1213
|
+
"(intro)": "214aa46eb3a895d5",
|
|
1214
|
+
"## Layout": "8baf49e4291e7e88",
|
|
1215
|
+
"## Commands (all through the pinned CLI in node_modules)": "d80ec56e4b4fc4c6",
|
|
1216
|
+
"## The site": "ab922bb6bde23293",
|
|
1217
|
+
"## Making games": "abf2f0d59341512d",
|
|
1218
|
+
"## The Game Codex and progress": "0738ef719cef3a4c",
|
|
1219
|
+
"## Art direction and models": "aaea65236db52126",
|
|
1220
|
+
"## Running live games (the back office)": "4aa5f513a7cd2c3b",
|
|
1221
|
+
"## Servers and AI seats": "98d08705087a33ec",
|
|
1222
|
+
"## Selling things (the shop)": "b04b0a2b25f524f2",
|
|
1223
|
+
"## Continuing a build from the Claude app": "0d68081e924ca419",
|
|
1224
|
+
"## Rules": "7e8458adc1b81ece",
|
|
1225
|
+
"## Beta": "9d02638207a26e73"
|
|
1226
|
+
}
|
|
1227
|
+
},
|
|
1228
|
+
"named": {
|
|
1229
|
+
"Homie Arcade": {
|
|
1230
|
+
"sections": {
|
|
1231
|
+
"AGENTS.md": {
|
|
1232
|
+
"## Commands (all through the pinned CLI in node_modules)": "b35df2c19cd4b534"
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1159
1237
|
}
|
|
1160
1238
|
}
|
|
1161
1239
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/* The animation card: each character's clips against the verbs the game needs, every one a small looping preview drawn
|
|
2
|
+
* by the game engine under the game's light (anim_preview), where it came from (its own, or the CC0 library's clips
|
|
3
|
+
* retargeted onto its skeleton), the verbs it lacks with Add (anim_add: free, baked into its skeleton's clip library),
|
|
4
|
+
* and Feel: the Game Lab on the move that plays it (game_lab with its take), New beside Today. */
|
|
5
|
+
(function () {
|
|
6
|
+
var C = Card;
|
|
7
|
+
var state = { busy: null };
|
|
8
|
+
function tile(r, c, sc) {
|
|
9
|
+
var t = C.el('div', 'clip' + (c.have ? '' : ' missing'));
|
|
10
|
+
var art = C.el('div', 'art');
|
|
11
|
+
var src = r.previews && r.previews[c.verb];
|
|
12
|
+
var i = src ? C.img(src, r.id + ' ' + c.verb) : null;
|
|
13
|
+
if (i) art.appendChild(i); else art.appendChild(C.el('span', '', c.have ? '…' : '+'));
|
|
14
|
+
t.appendChild(art);
|
|
15
|
+
t.appendChild(C.el('b', '', c.verb + (c.loop ? ' ↻' : '')));
|
|
16
|
+
t.appendChild(C.el('span', '', c.have ? (c.source ? c.source + (c.retargeted ? ' · retargeted' : '') : 'its own') : 'missing'));
|
|
17
|
+
if (!c.have) t.appendChild(C.btn(state.busy === r.id + c.verb ? 'Adding…' : 'Add (free)', 'small', function () {
|
|
18
|
+
state.busy = r.id + c.verb; C.render();
|
|
19
|
+
C.call('anim_add', { game: sc.game, asset: r.id, verbs: [c.verb] }).then(function (res) { state.busy = null; C.tell('clip:' + r.id + c.verb, 'The person added the ' + c.verb + ' clip to ' + r.id + ' on the animation card (free, retargeted onto its skeleton).'); C.take(res); }).catch(function () { state.busy = null; C.render(); });
|
|
20
|
+
}));
|
|
21
|
+
var take = sc.feel && sc.feel[c.verb];
|
|
22
|
+
if (c.have && take) t.appendChild(C.btn('Feel', 'ghost small', function () {
|
|
23
|
+
state.busy = 'Opening the Game Lab on “' + take + '”…'; C.render();
|
|
24
|
+
C.tell('feel:' + c.verb, 'The person pressed Feel on ' + r.id + '\'s ' + c.verb + ' clip: the Game Lab opens on the "' + take + '" take, New beside Today; its Motion sliders (fade, actSpeed, jumpStretch, landSquash, lean, ...) tune how it feels.');
|
|
25
|
+
C.call('game_lab', { game: sc.game, take: take }).then(function (res) { state.busy = null; C.take(res); }).catch(function () { state.busy = 'The Game Lab did not start.'; C.render(); });
|
|
26
|
+
}));
|
|
27
|
+
return t;
|
|
28
|
+
}
|
|
29
|
+
function render(sc) {
|
|
30
|
+
var card = C.el('main', 'card');
|
|
31
|
+
var rows = sc.rows || [];
|
|
32
|
+
var missing = rows.reduce(function (n, r) { return n + (r.missing || []).length; }, 0);
|
|
33
|
+
C.add(card, C.top('Clips', C.add(C.el('div', 'actions'), C.pill(missing ? missing + ' missing' : 'All there', missing ? 'warn' : 'ok'), C.fullscreenButton())),
|
|
34
|
+
C.el('h1', '', 'How the characters of ' + sc.game + ' move'),
|
|
35
|
+
C.el('p', 'sub', 'The game needs ' + (sc.verbs || []).join(', ') + '. Clips are baked into one library per skeleton at build time; every character on that skeleton shares it.'));
|
|
36
|
+
if (state.busy && !/^[a-z0-9-]+[a-z]+$/.test(state.busy)) card.appendChild(C.el('p', 'note', state.busy));
|
|
37
|
+
rows.forEach(function (r) {
|
|
38
|
+
var sec = C.el('section', 'chars');
|
|
39
|
+
sec.appendChild(C.add(C.el('div', 'dirhead'), C.el('b', '', r.id), C.el('span', '', r.familyLabel + ' · ' + r.bones + ' bones' + (r.animsKB ? ' · clips ' + r.animsKB + ' KB' : '') + ' · ' + r.route)));
|
|
40
|
+
if (r.shown) {
|
|
41
|
+
var grid = C.el('div', 'clips');
|
|
42
|
+
(r.clips || []).forEach(function (c) { grid.appendChild(tile(r, c, sc)); });
|
|
43
|
+
(r.extra || []).forEach(function (v) { grid.appendChild(tile(r, { verb: v, have: true, loop: false, source: null }, sc)); });
|
|
44
|
+
sec.appendChild(grid);
|
|
45
|
+
if (!r.previewed) sec.appendChild(C.btn(state.busy === 'draw' + r.id ? 'Drawing…' : 'Draw its clips (free)', 'ghost small', function () { state.busy = 'draw' + r.id; C.render(); C.call('anim_preview', { game: sc.game, asset: r.id }).then(function (res) { state.busy = null; C.take(res); }).catch(function () { state.busy = null; C.render(); }); }));
|
|
46
|
+
} else sec.appendChild(C.btn('Show its clips', 'ghost small', function () { C.call('anim_plan', { game: sc.game, asset: r.id }).then(C.take).catch(C.render); }));
|
|
47
|
+
card.appendChild(sec);
|
|
48
|
+
});
|
|
49
|
+
(sc.unrigged || []).forEach(function (u) { card.appendChild(C.el('p', 'fine', u + ' has no rig: a still model (the animate guide says how to rig one).')); });
|
|
50
|
+
var foot = C.el('div', 'foot');
|
|
51
|
+
foot.appendChild(C.el('span', 'when', Object.keys(sc.feel || {}).length ? 'Feel opens the Game Lab on this computer' : 'No Game Lab take yet: the lab guide adds one'));
|
|
52
|
+
card.appendChild(foot);
|
|
53
|
+
return card;
|
|
54
|
+
}
|
|
55
|
+
C.start({ kind: 'animation', label: 'Clips', fullscreen: true, render: render, poll: null });
|
|
56
|
+
})();
|
package/mcp/ui/card.css
CHANGED
|
@@ -88,3 +88,7 @@ input[type=text]{flex:1;min-width:0;font:14px/1.2 var(--f-sans);padding:8px 10px
|
|
|
88
88
|
.budget .track{height:8px;border-radius:4px;background:var(--c-bg3);overflow:hidden}.budget .track i{display:block;height:100%;background:var(--c-ok)}.budget .track i.over{background:var(--c-bad)}
|
|
89
89
|
details summary{cursor:pointer;color:var(--c-fg2);font-size:13px;margin-top:10px}
|
|
90
90
|
@media (max-width:420px){.card{padding:14px 12px 12px;border-radius:var(--r-md)}h1{font-size:18px}.stages{grid-auto-flow:row;grid-auto-columns:auto}.frame{height:520px}}
|
|
91
|
+
.chars{margin:12px 0 0;padding:10px;border-radius:var(--r-md);background:var(--c-bg2)}.chars .dirhead{margin-bottom:8px}
|
|
92
|
+
.clips{display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px}
|
|
93
|
+
.clip{display:grid;gap:3px;align-content:start;padding:6px;border-radius:var(--r-sm);background:var(--c-bg)}.clip .art{aspect-ratio:1;border-radius:var(--r-sm);background:var(--c-bg3);display:grid;place-items:center;overflow:hidden;color:var(--c-fg3);font-size:20px}.clip .art img{width:100%;height:100%;object-fit:cover}
|
|
94
|
+
.clip b{font-size:13px}.clip span{font-size:11.5px;color:var(--c-fg2);overflow-wrap:anywhere}.clip.missing{opacity:.8;box-shadow:inset 0 0 0 1px var(--c-line2)}.clip button{justify-self:start}
|
package/mcp/ui/cast.js
CHANGED
|
@@ -48,12 +48,46 @@
|
|
|
48
48
|
card.appendChild(grid);
|
|
49
49
|
card.appendChild(C.el('p', 'fine', 'Every item is CC0 (free for any use, no credit required), already phone-sized. Adding one copies it into the game: it never loads from anywhere else.'));
|
|
50
50
|
}
|
|
51
|
+
// The characters: the decisions that shape them, then each one made or planned, with its skeleton and clips.
|
|
52
|
+
function characters(card, sc) {
|
|
53
|
+
var d = sc.decisions || {};
|
|
54
|
+
var facts = C.el('ul', 'list decisions');
|
|
55
|
+
[['style.proportions', 'Proportions'], ['style.shape', 'Shape and silhouette'], ['cast.family', 'Library family'], ['rig.skeleton', 'Skeleton'], ['rig.source', 'Rigs from'], ['rig.bones', 'Bones']].forEach(function (k) {
|
|
56
|
+
var v = d[k[0]]; if (!v) return;
|
|
57
|
+
var li = C.el('li', v.state === 'locked' ? 'locked' : '');
|
|
58
|
+
li.appendChild(C.add(C.el('div', 'cb'), C.el('b', '', k[1] + ': ' + v.label), C.el('span', '', v.why || '')));
|
|
59
|
+
li.appendChild(C.pill(v.state, v.state === 'locked' ? 'ok' : ''));
|
|
60
|
+
facts.appendChild(li);
|
|
61
|
+
});
|
|
62
|
+
card.appendChild(facts);
|
|
63
|
+
var chips = C.el('div', 'chips');
|
|
64
|
+
(sc.palette || []).forEach(function (hex) { var s = C.el('span', 'swatch'); s.style.background = hex; s.title = hex; chips.appendChild(s); });
|
|
65
|
+
card.appendChild(C.add(C.el('p', 'fine', 'Palette and silhouette rule: ' + (sc.silhouette || '') + ' '), chips));
|
|
66
|
+
var list = C.el('ul', 'list cast');
|
|
67
|
+
(sc.rows || []).forEach(function (r) {
|
|
68
|
+
var li = C.el('li', r.state === 'made' ? 'done' : 'todo');
|
|
69
|
+
li.appendChild(thumb(r.thumb, r.id));
|
|
70
|
+
li.appendChild(C.add(C.el('div', 'cb'), C.el('b', '', r.id + (r.card ? ' · ' + r.card : '')), C.el('span', '', r.state === 'made' ? r.kind + ' · ' + (r.route === 'generated' ? 'generated (US$' + r.usd + ')' : r.route + (r.source ? ': ' + r.source : '')) + ' · ' + r.family + ' skeleton, ' + r.bones + ' bones · ' + r.tris + ' triangles · ' + r.heightM + ' m' : r.kind + ' · planned, ' + (r.heightM ? r.heightM + ' m' : 'no model yet')), r.verbs && r.verbs.length ? C.el('span', '', 'Clips: ' + r.verbs.join(', ')) : null));
|
|
71
|
+
var side = C.el('div', 'actions');
|
|
72
|
+
if (r.state === 'made') side.appendChild(C.btn('Clips', 'ghost small', function () { C.call('anim_plan', { game: sc.game, asset: r.id }).then(C.take).catch(C.render); }));
|
|
73
|
+
else {
|
|
74
|
+
side.appendChild(C.btn('Find in the library', 'small', function () { C.call('assets_find', { game: sc.game, query: r.id.replace(/-/g, ' '), kind: r.kind }).then(C.take).catch(C.render); }));
|
|
75
|
+
side.appendChild(C.btn('Generate', 'ghost small', function () { C.tell('char:' + r.id, 'The person wants ' + r.id + ' (' + (r.card || r.kind) + ') generated as a rigged character: price it with character_make (a dry run, about US$1.44) and ask before paying.'); busy[r.id] = 'Asked your AI to price it'; C.render(); }));
|
|
76
|
+
}
|
|
77
|
+
if (busy[r.id]) side.appendChild(C.el('span', 'fine', busy[r.id]));
|
|
78
|
+
li.appendChild(side);
|
|
79
|
+
list.appendChild(li);
|
|
80
|
+
});
|
|
81
|
+
card.appendChild(list);
|
|
82
|
+
card.appendChild(C.el('p', 'fine', 'Library characters are free (CC0); a generated one is about US$1.44 on your own fal account, priced and asked for first. Spent so far: US$' + (sc.spend ? sc.spend.used.toFixed(2) : '0.00') + '.'));
|
|
83
|
+
}
|
|
51
84
|
function render(sc) {
|
|
52
85
|
var card = C.el('main', 'card');
|
|
53
|
-
var title = sc.mode === 'find' ? 'Free models for “' + sc.query + '”' : sc.mode === 'added' ? 'Added ' + (sc.added && sc.added.asset) : 'The cast of ' + sc.game;
|
|
54
|
-
C.add(card, C.top('Cast', sc.mode === 'plan' ? C.pill((sc.rows || []).filter(function (r) { return r.state === 'made'; }).length + ' of ' + (sc.rows || []).length + ' made', '') : null), C.el('h1', '', title));
|
|
86
|
+
var title = sc.mode === 'find' ? 'Free models for “' + sc.query + '”' : sc.mode === 'added' ? 'Added ' + (sc.added && sc.added.asset) : sc.mode === 'characters' ? 'The characters of ' + sc.game : 'The cast of ' + sc.game;
|
|
87
|
+
C.add(card, C.top('Cast', sc.mode === 'characters' ? C.pill((sc.rows || []).filter(function (r) { return r.state === 'made'; }).length + ' made', '') : sc.mode === 'plan' ? C.pill((sc.rows || []).filter(function (r) { return r.state === 'made'; }).length + ' of ' + (sc.rows || []).length + ' made', '') : null), C.el('h1', '', title));
|
|
55
88
|
if (sc.library && sc.library.error) card.appendChild(C.el('p', 'note', 'Starter library: ' + sc.library.error));
|
|
56
89
|
if (sc.mode === 'plan') plan(card, sc);
|
|
90
|
+
else if (sc.mode === 'characters') characters(card, sc);
|
|
57
91
|
else if (sc.mode === 'find') find(card, sc);
|
|
58
92
|
else if (sc.added) card.appendChild(C.el('p', 'sub', sc.added.asset + ' is in games/' + sc.game + (sc.added.after ? ': ' + sc.added.after.tris + ' triangles, ' + sc.added.after.kb + ' KB' : '') + '. Licence: ' + (sc.added.license || 'CC0') + '.'));
|
|
59
93
|
return card;
|
package/mcp/ui/lineup.js
CHANGED
|
@@ -37,25 +37,25 @@
|
|
|
37
37
|
var a = { game: sc.game, asset: sc.asset };
|
|
38
38
|
for (var q in (sc.request || {})) a[q] = sc.request[q];
|
|
39
39
|
for (var k in args) a[k] = args[k];
|
|
40
|
-
C.call('asset_make', a).then(function (r) { state.busy = null; C.take(r); }).catch(function () { state.busy = 'That did not reach the studio.'; C.render(); });
|
|
40
|
+
C.call(sc.character ? 'character_make' : 'asset_make', a).then(function (r) { state.busy = null; C.take(r); }).catch(function () { state.busy = 'That did not reach the studio.'; C.render(); });
|
|
41
41
|
};
|
|
42
42
|
if (sc.concept) { var i = C.img(sc.concept, 'The concept for ' + sc.asset); if (i) { i.style.maxHeight = '360px'; i.style.objectFit = 'contain'; card.appendChild(C.add(C.el('div', 'preview'), i)); } }
|
|
43
43
|
if (sc.dryRun) {
|
|
44
|
-
card.appendChild(C.el('p', 'sub', (sc.step === 'mesh' ? 'The 3D model' : 'The concept image') + ' costs about US$' + (sc.price ? sc.price.usd : '?') + (sc.total ? '; the whole prop about US$' + sc.total : '') + ', on your own fal account.'));
|
|
44
|
+
card.appendChild(C.el('p', 'sub', (sc.step === 'mesh' ? (sc.character ? 'The rigged character' : 'The 3D model') : 'The concept image') + ' costs about US$' + (sc.price ? sc.price.usd : '?') + (sc.total ? '; the whole ' + (sc.character ? 'character' : 'prop') + ' about US$' + sc.total : '') + ', on your own fal account.'));
|
|
45
45
|
card.appendChild(C.add(C.el('div', 'actions'), C.btn('Make it (US$' + (sc.price ? sc.price.usd : '?') + ')', '', function () { C.tell('approve:' + sc.asset + sc.step, 'The person approved US$' + (sc.price && sc.price.usd) + ' for the ' + sc.step + ' of ' + sc.asset + ' on the card.'); run({ step: sc.step, approve: true }, 'Making it…'); })));
|
|
46
46
|
} else if (sc.needs === 'approval' || sc.why) card.appendChild(C.el('p', 'note', sc.why || 'Needs the person\'s yes.'));
|
|
47
47
|
else if ((sc.step === 'concept' || sc.step === 'look') && sc.concept) {
|
|
48
|
-
card.appendChild(C.el('p', 'sub', 'Look at it: the thing, whole, in the game\'s style, on a plain background? Then the 3D model (about US$' + (sc.then ? sc.then.usd : '0.50') + ').'));
|
|
49
|
-
card.appendChild(C.add(C.el('div', 'actions'), C.btn('Make the 3D model', '', function () { C.tell('mesh:' + sc.asset, 'The person approved the 3D model of ' + sc.asset + ' (about US$' + (sc.then ? sc.then.usd : '0.50') + ') on the card.'); run({ step: 'mesh', approve: true }, 'Making the model (1 to 3 minutes)…'); })));
|
|
48
|
+
card.appendChild(C.el('p', 'sub', sc.character ? 'Look at it: one character, whole, in an A-pose, in the game\'s style, on a plain background? Then the rigged 3D character (about US$' + (sc.then ? sc.then.usd : '1.40') + '); its clips come from the free library.' : 'Look at it: the thing, whole, in the game\'s style, on a plain background? Then the 3D model (about US$' + (sc.then ? sc.then.usd : '0.50') + ').'));
|
|
49
|
+
card.appendChild(C.add(C.el('div', 'actions'), C.btn(sc.character ? 'Make the rigged character' : 'Make the 3D model', '', function () { C.tell('mesh:' + sc.asset, 'The person approved the ' + (sc.character ? 'rigged character' : '3D model') + ' of ' + sc.asset + ' (about US$' + (sc.then ? sc.then.usd : sc.character ? '1.40' : '0.50') + ') on the card.'); run({ step: 'mesh', approve: true }, sc.character ? 'Making the rigged character (2 to 5 minutes)…' : 'Making the model (1 to 3 minutes)…'); })));
|
|
50
50
|
} else if (sc.step === 'mesh' && sc.after) {
|
|
51
|
-
card.appendChild(C.el('p', 'note ok', sc.asset + ': ' + sc.before.tris + ' → ' + sc.after.tris + ' triangles, ' + sc.after.kb + ' KB, ' + sc.after.heightM + ' m. Recorded with its receipts and licence.'));
|
|
52
|
-
card.appendChild(C.add(C.el('div', 'actions'), C.btn('Show the lineup', 'ghost', function () { state.busy = 'Drawing the lineup…'; C.render(); C.call('asset_lineup', { game: sc.game }).then(function (r) { state.busy = null; C.take(r); }); })));
|
|
51
|
+
card.appendChild(C.el('p', 'note ok', sc.asset + ': ' + sc.before.tris + ' → ' + sc.after.tris + ' triangles, ' + sc.after.kb + ' KB, ' + sc.after.heightM + ' m. Recorded with its receipts and licence.' + (sc.character && sc.verbs && sc.verbs.length ? ' Clips (the library\'s, retargeted, free): ' + sc.verbs.join(', ') + '.' : '')));
|
|
52
|
+
card.appendChild(C.add(C.el('div', 'actions'), C.btn('Show the lineup', 'ghost', function () { state.busy = 'Drawing the lineup…'; C.render(); C.call('asset_lineup', { game: sc.game }).then(function (r) { state.busy = null; C.take(r); }); }), sc.character ? C.btn('Show its clips', 'ghost', function () { state.busy = 'Drawing its clips…'; C.render(); C.call('anim_preview', { game: sc.game, asset: sc.asset }).then(function (r) { state.busy = null; C.take(r); }); }) : null));
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
function render(sc) {
|
|
56
56
|
var card = C.el('main', 'card');
|
|
57
57
|
var flagged = sc.mode === 'lineup' ? sc.flagged : null;
|
|
58
|
-
C.add(card, C.top(sc.mode === 'make' ? 'Make a prop' : 'Lineup', C.add(C.el('div', 'actions'), flagged !== null && flagged !== undefined ? C.pill(flagged ? flagged + ' flagged' : 'One look', flagged ? 'warn' : 'ok') : null, C.fullscreenButton())),
|
|
58
|
+
C.add(card, C.top(sc.mode === 'make' ? (sc.character ? 'Make a character' : 'Make a prop') : 'Lineup', C.add(C.el('div', 'actions'), flagged !== null && flagged !== undefined ? C.pill(flagged ? flagged + ' flagged' : 'One look', flagged ? 'warn' : 'ok') : null, C.fullscreenButton())),
|
|
59
59
|
C.el('h1', '', sc.mode === 'make' ? sc.asset : 'The cast of ' + sc.game + ', at true scale'));
|
|
60
60
|
if (state.busy) card.appendChild(C.el('p', 'note', state.busy));
|
|
61
61
|
if (sc.mode === 'make') make(card, sc); else lineup(card, sc);
|
package/netplay/NETPLAY.md
CHANGED
|
@@ -1340,16 +1340,20 @@ ticker.
|
|
|
1340
1340
|
### What the page does (worker/chat-page.mjs)
|
|
1341
1341
|
|
|
1342
1342
|
- **Play:** a Chat pill in the room button's band (game.json `screen.share` already keeps that
|
|
1343
|
-
corner clear of the game's HUD
|
|
1343
|
+
corner clear of the game's HUD; a round icon on a phone and beside a room button kept an icon,
|
|
1344
|
+
and on a computer wherever its word would reach the middle third of the top), with a count of
|
|
1345
|
+
unread lines; its sheet: the room's last
|
|
1344
1346
|
minutes, a row of reactions (2.5 rem circles that pop), the quick lines, typing where the rules
|
|
1345
1347
|
allow it (and why not where they do not: "Sign in to type here. Emoji are open to everyone."),
|
|
1346
1348
|
Report on a line, and two switches kept in this browser: **Show my messages over my character**
|
|
1347
|
-
and **Show chat on this screen** (off: no
|
|
1348
|
-
show for a moment where the status chip sits
|
|
1349
|
-
|
|
1349
|
+
and **Show chat on this screen** (off: no strip, no float, no bubbles in this game). New lines
|
|
1350
|
+
show for a moment where the status chip sits; game.json `"screen": { "chat": … }` moves that
|
|
1351
|
+
strip per device (`at`, `x` / `y`, `desk`, `phone`, `sideways`, `tv`) or keeps new lines in the
|
|
1352
|
+
sheet (`"lines": "sheet-only"`, or `false`: only the pill's count). chat/CHAT.md has the fields.
|
|
1350
1353
|
- **Float:** every reaction rises up every screen in the room, as on the television: at most six
|
|
1351
1354
|
a second and eighteen at once, 2.4 s each with a little sway. The sender's own floats at once.
|
|
1352
|
-
- **TV** (`/<game>/tv`): the room's lines in the corner the QR card does not use
|
|
1355
|
+
- **TV** (`/<game>/tv`): the room's lines in the corner the QR card does not use (or game.json
|
|
1356
|
+
`screen.chat`'s corner), no typing.
|
|
1353
1357
|
- **Watch:** a Chat button in the band; its panel over the stage (a bottom sheet on a phone).
|
|
1354
1358
|
|
|
1355
1359
|
**Privacy.** Nothing a person says is stored: the room keeps the last 50 lines of the last 15
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@homie-rocks/studio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "A studio for games, music and video on its own Cloudflare: scaffold, multiplayer starters on the netplay contract, a port toolkit that makes existing single-player web games multiplayer, the site Worker with public rooms (Table/Lobby Durable Objects and D1, all on the free Workers plan, no payment method), a site with the hub's sections (Home, Games, Music, Videos, Rooms, Posts with feeds) in the studio's own look, an epic landing page for every game, big songs and videos in the studio's own R2 once it has storage (uploaded, checked by SHA-256, served at the same addresses), deploy, and the homie.rocks directory.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -46,6 +46,10 @@
|
|
|
46
46
|
"types": "./assets/assets.ts",
|
|
47
47
|
"default": "./assets/assets.ts"
|
|
48
48
|
},
|
|
49
|
+
"./animate": {
|
|
50
|
+
"types": "./assets/animate.ts",
|
|
51
|
+
"default": "./assets/animate.ts"
|
|
52
|
+
},
|
|
49
53
|
"./worker": "./worker/index.mjs",
|
|
50
54
|
"./package.json": "./package.json"
|
|
51
55
|
},
|
package/site/SITE.md
CHANGED
|
@@ -169,6 +169,10 @@ where the game has room, per device:
|
|
|
169
169
|
- A button at the bottom left sends the "finding a room" chip to the bottom right.
|
|
170
170
|
- On a server, the server's pill sits beside the button, on its inner side in the same band, never under it: on a
|
|
171
171
|
phone held upright it is one more dot; elsewhere its name shows for a few seconds, then it is a dot too.
|
|
172
|
+
- Room chat's Chat pill sits in the same band: a round icon on a phone (either way up) and beside a button kept an
|
|
173
|
+
icon; on a computer it says "Chat" unless the word would take the band off the screen or into the middle third of
|
|
174
|
+
its width, where games keep a clock or a title. Its strip of new lines (bottom left by default) moves with
|
|
175
|
+
`"screen": { "chat": … }`, per device, or stays in the Chat sheet (`"lines": "sheet-only"`): chat/CHAT.md.
|
|
172
176
|
|
|
173
177
|
Look at the play page on a computer and a phone (both ways up) once a round is on: the button must not sit on a
|
|
174
178
|
score, a timer or a bar. A room code the relay cannot use (1 to 32 letters, digits, `-` or `_`) is refused
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Rights: Hero Rush 3D
|
|
2
|
+
|
|
3
|
+
Every file this game ships, where it came from, its licence and what that allows. Written by `homie-studio assets rights hero-rush-3d` from `assets/manifest.json`; do not edit it by hand.
|
|
4
|
+
|
|
5
|
+
## What the providers' terms say
|
|
6
|
+
|
|
7
|
+
Read on the dates shown. Terms change: read the live page again before publishing anything commercial.
|
|
8
|
+
|
|
9
|
+
- **KayKit** (https://kaylousberg.itch.io/, read 2026-10-02): CC0 1.0: free for personal and commercial use, no attribution required.
|
|
10
|
+
|
|
11
|
+
## Files
|
|
12
|
+
|
|
13
|
+
### barbarian
|
|
14
|
+
|
|
15
|
+
- **What:** character (Players/Barbarian): `public/models/barbarian.glb`
|
|
16
|
+
- **From:** from the Homie starter library: KayKit Adventurers, barbarian (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Adventures-1.0); library
|
|
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
|
+
- **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
|
+
|
|
21
|
+
### barrel
|
|
22
|
+
|
|
23
|
+
- **What:** prop (Places/Barrel): `public/models/barrel.glb`
|
|
24
|
+
- **From:** from the Homie starter library: KayKit Medieval Hexagon, barrel (https://github.com/KayKit-Game-Assets/KayKit-Medieval-Hexagon-Pack-1.0); library
|
|
25
|
+
- **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
|
+
- **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
|
+
|
|
29
|
+
### chest
|
|
30
|
+
|
|
31
|
+
- **What:** prop (Places/Treasure Chest): `public/models/chest.glb`
|
|
32
|
+
- **From:** from the Homie starter library: KayKit Dungeon Remastered, chest-gold (https://github.com/KayKit-Game-Assets/KayKit-Dungeon-Remastered-1.0); library
|
|
33
|
+
- **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
|
+
- **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
|
+
|
|
37
|
+
### coin
|
|
38
|
+
|
|
39
|
+
- **What:** prop (Items/Coin): `public/models/coin.glb`
|
|
40
|
+
- **From:** from the Homie starter library: KayKit Dungeon Remastered, coin (https://github.com/KayKit-Game-Assets/KayKit-Dungeon-Remastered-1.0); library
|
|
41
|
+
- **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
|
+
- **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
|
+
|
|
45
|
+
### crate
|
|
46
|
+
|
|
47
|
+
- **What:** prop (Places/Crate): `public/models/crate.glb`
|
|
48
|
+
- **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
|
+
- **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
|
+
- **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
|
+
|
|
53
|
+
### grove
|
|
54
|
+
|
|
55
|
+
- **What:** prop (Places/Grove): `public/models/grove.glb`
|
|
56
|
+
- **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
|
+
- **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
|
+
- **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
|
+
|
|
61
|
+
### knight
|
|
62
|
+
|
|
63
|
+
- **What:** character (Players/Knight): `public/models/knight.glb`
|
|
64
|
+
- **From:** from the Homie starter library: KayKit Adventurers, knight (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Adventures-1.0); library
|
|
65
|
+
- **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
|
+
- **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
|
+
|
|
69
|
+
### mage
|
|
70
|
+
|
|
71
|
+
- **What:** character (Players/Mage): `public/models/mage.glb`
|
|
72
|
+
- **From:** from the Homie starter library: KayKit Adventurers, mage (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Adventures-1.0); library
|
|
73
|
+
- **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
|
+
- **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
|
+
|
|
77
|
+
### pine
|
|
78
|
+
|
|
79
|
+
- **What:** prop (Places/Pine): `public/models/pine.glb`
|
|
80
|
+
- **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
|
+
- **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
|
+
- **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
|
+
|
|
85
|
+
### pine-round
|
|
86
|
+
|
|
87
|
+
- **What:** prop (Places/Round Pine): `public/models/pine-round.glb`
|
|
88
|
+
- **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
|
+
- **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
|
+
- **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
|
+
|
|
93
|
+
### rock
|
|
94
|
+
|
|
95
|
+
- **What:** prop (Places/Rock): `public/models/rock.glb`
|
|
96
|
+
- **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
|
+
- **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
|
+
- **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
|
+
|
|
101
|
+
### rocks
|
|
102
|
+
|
|
103
|
+
- **What:** prop (Places/Rocks): `public/models/rocks.glb`
|
|
104
|
+
- **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
|
+
- **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
|
+
- **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
|
+
|
|
109
|
+
### rogue
|
|
110
|
+
|
|
111
|
+
- **What:** character (Players/Rogue): `public/models/rogue.glb`
|
|
112
|
+
- **From:** from the Homie starter library: KayKit Adventurers, rogue (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Adventures-1.0); library
|
|
113
|
+
- **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
|
+
- **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
|
+
|
|
117
|
+
### rogue-hooded
|
|
118
|
+
|
|
119
|
+
- **What:** character (Players/Hooded Rogue): `public/models/rogue-hooded.glb`
|
|
120
|
+
- **From:** from the Homie starter library: KayKit Adventurers, rogue-hooded (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Adventures-1.0); library
|
|
121
|
+
- **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
|
+
- **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
|
+
|
|
125
|
+
### skeleton-mage
|
|
126
|
+
|
|
127
|
+
- **What:** creature (Creatures/Skeleton Mage): `public/models/skeleton-mage.glb`
|
|
128
|
+
- **From:** from the Homie starter library: KayKit Skeletons, skeleton-mage (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Skeletons-1.0); library
|
|
129
|
+
- **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
|
+
- **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
|
+
|
|
133
|
+
### skeleton-minion
|
|
134
|
+
|
|
135
|
+
- **What:** creature (Creatures/Skeleton Minion): `public/models/skeleton-minion.glb`
|
|
136
|
+
- **From:** from the Homie starter library: KayKit Skeletons, skeleton-minion (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Skeletons-1.0); library
|
|
137
|
+
- **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
|
+
- **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
|
+
|
|
141
|
+
### skeleton-rogue
|
|
142
|
+
|
|
143
|
+
- **What:** creature (Creatures/Skeleton Rogue): `public/models/skeleton-rogue.glb`
|
|
144
|
+
- **From:** from the Homie starter library: KayKit Skeletons, skeleton-rogue (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Skeletons-1.0); library
|
|
145
|
+
- **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
|
+
- **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
|
+
|
|
149
|
+
### skeleton-warrior
|
|
150
|
+
|
|
151
|
+
- **What:** creature (Creatures/Skeleton Warrior): `public/models/skeleton-warrior.glb`
|
|
152
|
+
- **From:** from the Homie starter library: KayKit Skeletons, skeleton-warrior (https://github.com/KayKit-Game-Assets/KayKit-Character-Pack-Skeletons-1.0); library
|
|
153
|
+
- **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
|
+
- **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
|
+
|
|
157
|
+
### torch
|
|
158
|
+
|
|
159
|
+
- **What:** prop (Places/Torch): `public/models/torch.glb`
|
|
160
|
+
- **From:** from the Homie starter library: KayKit Dungeon Remastered, torch-lit (https://github.com/KayKit-Game-Assets/KayKit-Dungeon-Remastered-1.0); library
|
|
161
|
+
- **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
|
+
- **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.
|