muse-engine-32 / index.html
axonis22's picture
Muse Engine 32: your FBX/GLB scene as the level, skinned characters, Model check, save/load setup
6c78aa4 verified
Raw History Blame Contribute Delete
18.9 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Muse Engine 32 RC - Save / Load + Model Check</title>
<style>
:root {
--bg: #070a10;
--panel: rgba(12, 18, 28, 0.92);
--line: #1e2a3c;
--text: #d7e6ff;
--muted: #8aa0c0;
--accent: #5ec8ff;
--ok: #3ecf8e;
--warn: #e6b84d;
--freeze: #6ea8ff;
--next: #b388ff;
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--text);
font-family: "Segoe UI", system-ui, Roboto, sans-serif; }
body { display: grid; grid-template-columns: 340px 1fr; min-height: 100vh; }
#side {
background: var(--panel); border-right: 1px solid var(--line);
padding: 16px 14px 24px; overflow-y: auto; z-index: 2;
}
#side h1 { margin: 0 0 4px; font-size: 16px; letter-spacing: .3px; }
#side .sub { color: var(--muted); font-size: 12px; margin-bottom: 14px; line-height: 1.35; }
.btnrow { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
a.btn, button.btn {
display: inline-block; text-decoration: none; color: #061018; background: var(--freeze);
border: 0; border-radius: 8px; padding: 8px 12px; font-size: 12px; font-weight: 600;
cursor: pointer;
}
a.btn.secondary, button.btn.secondary { background: #243247; color: var(--text); }
a.btn.ok { background: var(--ok); color: #042016; }
.section { margin-top: 16px; }
.section h2 { margin: 0 0 8px; font-size: 12px; text-transform: uppercase;
letter-spacing: .08em; color: var(--muted); }
.phases { display: flex; flex-direction: column; gap: 6px; }
.phase {
border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px;
background: rgba(255,255,255,0.02); cursor: pointer;
}
.phase:hover { border-color: #2f4058; }
.phase.active { border-color: var(--next); box-shadow: 0 0 0 1px rgba(179,136,255,.35); }
.phase .top { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.phase .num { font-weight: 700; font-size: 13px; }
.phase .tag {
font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
padding: 2px 6px; border-radius: 999px; background: #1a2433; color: var(--muted);
}
.phase .tag.done { background: rgba(62,207,142,.15); color: var(--ok); }
.phase .tag.now { background: rgba(179,136,255,.18); color: #d2b8ff; }
.phase .tag.park { background: rgba(230,184,77,.14); color: var(--warn); }
.phase .tag.plan { background: rgba(110,168,255,.12); color: var(--freeze); }
.phase p { margin: 4px 0 0; font-size: 11px; color: var(--muted); line-height: 1.35; }
.checks label {
display: flex; gap: 8px; align-items: flex-start; font-size: 12px;
color: var(--text); margin: 6px 0; cursor: pointer;
}
.checks input { margin-top: 2px; }
.note {
font-size: 11px; color: var(--muted); line-height: 1.4;
border-left: 2px solid var(--line); padding-left: 8px; margin-top: 8px;
}
#stage { position: relative; min-height: 100vh; background: #05070c; }
#muse-canvas { display: block; width: 100%; height: 100vh; cursor: grab; background: #06080c; }
#muse-canvas:active { cursor: grabbing; }
#hud {
position: absolute; left: 12px; bottom: 12px; color: #cfe8ff; font-size: 12px;
background: rgba(0,0,0,.4); padding: 6px 10px; border-radius: 8px; pointer-events: none;
}
#banner {
position: absolute; left: 12px; top: 12px; right: 12px; max-width: 520px;
background: rgba(0,0,0,.45); color: #9ecbff; font-size: 12px;
padding: 8px 10px; border-radius: 8px; pointer-events: none; line-height: 1.35;
}
#credit {
position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
background: rgba(0,0,0,.75); color: #fff; padding: 20px 28px; border-radius: 14px;
text-align: center; pointer-events: none; opacity: 0; transition: opacity .6s; z-index: 5;
}
#credit.show { opacity: 1; }
#credit h1 { margin: 0 0 6px; font-size: 20px; }
#credit p { margin: 4px 0; color: #bcd6ff; font-size: 12px; }
/* [e30] hide the lab sidebar (H) so the game view gets the whole window */
body.noside { grid-template-columns: 1fr; } /* #side is display:none, so the game view takes the only column */
body.noside #side { display: none; }
#e30-side-toggle { position: fixed; left: 8px; bottom: 8px; z-index: 30; font-size: 11px; padding: 4px 8px; border-radius: 6px;
border: 1px solid #2f4058; background: rgba(12,18,28,.85); color: #d7e6ff; cursor: pointer; display: none; }
body.noside #e30-side-toggle { display: block; }
@media (max-width: 900px) {
body { grid-template-columns: 1fr; }
#side { max-height: 42vh; }
#muse-canvas { height: 58vh; }
}
#side .note a { color: #7fc4ff; }
</style>
<link rel="stylesheet" href="engine/ui/e29-ui.css?v=e32-rc-1" />
<script type="importmap">
{ "imports": { "three": "./engine/vendor/three/three.core.min.js", "three/addons/": "./engine/vendor/three/addons/" } }
</script>
</head>
<body>
<aside id="side">
<h1>Muse Engine 32 RC · Save / Load + Model Check</h1>
<div class="sub">Engine 32 RC: save / load the whole setup as JSON, drag-and-drop models onto the game view, a Model check panel that explains export problems (with the fix), root motion stripped so walk cycles stay in place, and a HOWTO for Maya / 3ds Max users. Load your own animated character (skinned FBX from Maya / 3ds Max, or GLB) as the enemies: GPU-skinned, clips mapped by name, walk / run / shoot / death, fitted capsule and head / body hitboxes. Load your own scene as the level: units and up-axis converted, walk and collide on its geometry. Two switchable looks (Look B by Muse Glimmer). Raw WebGL1 renderer by Muse Glimmer, coached by Grok Bot, hosted by Axonis Pty Limited (Paul Buckingham).</div>
<div class="section">
<h2>Look</h2>
<div class="btnrow" id="look-buttons"></div>
<p class="note" id="look-note">L cycles looks in-game · Tab opens the config panel (look, model import, gameplay toggles). Visuals only: colliders and hitboxes are the same in every look.</p>
</div>
<div class="btnrow">
<button class="btn" type="button" id="btn-config">Config (Tab)</button>
<button class="btn secondary" type="button" id="btn-credit">Flash credit</button>
<button class="btn secondary" type="button" id="btn-focus">Focus canvas</button>
<button class="btn secondary" type="button" id="btn-side">Hide sidebar (H)</button>
</div>
<div class="section">
<h2>Phases 24 → 32</h2>
<div class="phases" id="phase-list"></div>
<p class="note">Select a phase to mark the lab focus (saved in this browser).</p>
</div>
<div class="section">
<h2>Look / model checks (Phase 25–27+)</h2>
<div class="checks" id="look-checks">
<label><input type="checkbox" data-k="normals" /> Normals readable at distance (outside shapes)</label>
<label><input type="checkbox" data-k="tex" /> Base-color textures / material reads (paint, metal, rubber)</label>
<label><input type="checkbox" data-k="nm" /> Phase 26: normal maps sample on look GLB (ToyCar NM)</label>
<label><input type="checkbox" data-k="bollard" /> Phase 27: Mooring Bollard visible (Key K toggle)</label>
<label><input type="checkbox" data-k="glb" /> At least one showroom-grade textured GLB in look pack</label>
<label><input type="checkbox" data-k="toycar" /> Bar = showroom end cars (Khronos textured GLB preferred)</label>
<label><input type="checkbox" data-k="lookb" /> Look B (Muse) swap tested with L (game still playable)</label>
<label><input type="checkbox" data-k="parkour28" /> Phase 28: parkour steps + ladder climb + Space jump</label>
<label><input type="checkbox" data-k="combat29" /> Phase 29: hostiles blocked by buildings + fall-then-boom kills</label>
<label><input type="checkbox" data-k="level30" /> Phase 30: FBX (Z-up, cm) and GLB scenes load upright at real scale, textured, walkable with colliders</label>
<label><input type="checkbox" data-k="aim30" /> Phase 30: crosshair on the shot point (sidebar shown and hidden); lamp1 shootable from spawn</label>
<label><input type="checkbox" data-k="anim31" /> Phase 31: skinned character (FBX Character1: rig + GLB) animates as the enemies, clips mapped, headshots</label>
<label><input type="checkbox" data-k="setup32" /> Phase 32: save setup, reload page, load setup (and drag-and-drop) restores scene + character + picks</label>
<label><input type="checkbox" data-k="check32" /> Phase 32: Model check warnings make sense for your own Maya / 3ds Max exports</label>
</div>
</div>
<div class="section" id="e32-docs">
<h2>For Maya / 3ds Max users</h2>
<p class="note"><a href="docs/HOWTO-AUTODESK.md" target="_blank" rel="noopener" id="side-howto">HOWTO: export scenes and rigs for Muse Engine</a> (units, up axis, UCX_ / _col / _nocol / PlayerStart, 60-bone limit, bake, embed media) · <a href="assets/testpack/muse-engine-32-testpack-cc0.zip" download id="side-testpack">CC0 test pack (.zip)</a> · Tab → Model check explains what the engine found in your file.</p>
</div>
<div class="section">
<h2>Controls (current engine)</h2>
<p class="note">Click to aim · WASD move · Mouse look · Space jump · LMB shoot · R reload · E door · Ctrl crouch · N night · <b>L</b> next look · <b>Tab</b> config panel (load a scene as level) · <b>H</b> hide/show sidebar · Shift+L load a GLB prop · <b>drag files</b> onto the game view (scene left, character right, setup .json anywhere) · K bollard on/off · T char shapes · O orbit cam · C credit · Esc release mouse</p>
</div>
</aside>
<main id="stage">
<canvas id="muse-canvas"></canvas>
<div id="banner">Muse Engine 32 RC · drop a scene (left) or character (right) on the game view · Tab = config (save / load setup, Model check) · L = next look · H = hide sidebar</div>
<div id="hud">Muse Glimmer · Muse Engine 32 RC</div>
<div id="credit">
<h1>MUSE ENGINE 32 RC</h1>
<p>WebGL1 · your scene as the level · your rig as the enemies · save / load</p>
<p>Muse Glimmer, coached by Grok Bot, hosted by Axonis Pty Limited (Paul Buckingham)</p>
</div>
</main>
<button id="e30-side-toggle" type="button">Show sidebar (H)</button>
<script>
(function () {
var PHASES = [
{ n: 24, tag: 'done', title: 'Freeze', blurb: 'Mitsh polish + Mitch parkour jump-blocks. Playable. Climb/ladder experiments parked in TRACK.' },
{ n: 25, tag: 'done', title: 'Lean + look', blurb: 'Leaner scene + shootable hostiles. Textured multi-mesh GLB (textured GLB). Key K look toggle. Climb/jump/parkour frozen from P24.' },
{ n: 26, tag: 'done', title: 'Normal maps (NM)', blurb: 'Sample GLB normalTexture on look props (bay look GLB via Key L). TBN from tangents/UV. Ladder/jumps still PARKED in TRACK — not this phase.' },
{ n: 27, tag: 'done', title: 'Mooring Bollard mesh', blurb: 'Muse pick: pierMooringBollard - in-engine bollard near pier. Key K. TEX+NM kept.' },
{ n: 28, tag: 'done', title: 'Parkour Climb', blurb: 'Land on tops, coyote/buffer jump, step-up/mantle, climbable ladder + short parkour route right of spawn. Movement-only; look/shoot kept.' },
{ n: 29, tag: 'done', title: 'Combat Feel + Look Picker', blurb: 'Hostile solid AABB vs buildings/props (no wall-clip). Kill = visible fall/tip then boom/despawn. This release adds a look picker: Look A (Phase 29) / Look B (Muse).' },
{ n: 30, tag: 'done', title: 'Scene Level (your scene = the level)', blurb: 'Load an FBX (Maya / 3ds Max, Z-up or Y-up, cm / m / inch) or GLB / glTF scene: units + up-axis converted, textures kept, walkable floors + wall colliders generated from the mesh (collider + units modules written by Muse Glimmer, reviewed and fixed by Grok Bot), step-up / mantle on your geometry, spawn on PlayerStart or open floor, enemies placed on the floor. Toggle back to built-in colliders. CC0 Kenney Yard test scenes (FBX Z-up cm + GLB). Fixes: crosshair on the shot point, pyramid hitbox.' },
{ n: 31, tag: 'done', title: 'Animated Characters (your rig = the enemies)', blurb: 'Load a skinned character (FBX from Maya / 3ds Max / Mixamo-style rigs with Character1: or mixamorig: namespaces, several takes, 30 fps bakes; or GLB): GPU skinning (4 weights, up to 60 bones, extra bones merged), units + up-axis converted, clips auto-mapped by name (idle / walk / run / shoot / death) with a picker for the rest, walk vs run by speed with a 0.2 s crossfade, death clip replaces fall-then-boom, capsule fitted from the bind pose, head + body hitboxes (headshot x3), placed on the level floor. Clip matcher, capsule / head fit, pose + crossfade and bone budget written by Muse Glimmer, reviewed and fixed by Grok Bot. CC0 Quaternius SWAT test characters (FBX Z-up cm + GLB).' },
{ n: 32, tag: 'now', title: 'Save / Load + Model Check (Engine 32 RC)', blurb: 'Save / load the whole setup as one JSON file (scene, character, units / up, clip picks, look, toggles) and drag-and-drop models or a setup onto the game view (left half = scene, right half = character). Model check panel: bones (merged ones marked), takes with fps / frames / length, triangles, colliders, textures, and warnings with the fix (no skin, over 60 bones, root motion, missing textures, heavy mesh, no unit / up info). Strip root motion toggle (on by default) and dogs use the loaded character. Loading progress, clear error messages, faster heavy scenes (batched parts, frustum culling, shared textures). HOWTO for Maya / 3ds Max users and a CC0 test pack. Model check, root motion and setup schema written by Muse Glimmer, reviewed and fixed by Grok Bot.' }
];
var list = document.getElementById('phase-list');
var hud = document.getElementById('hud');
var banner = document.getElementById('banner');
var key = 'muse-engine-29.lab';
var state = { phase: 32, checks: {} };
try {
var raw = localStorage.getItem(key);
if (raw) state = Object.assign(state, JSON.parse(raw));
} catch (e) {}
var q = new URLSearchParams(location.search).get('phase');
if (q && !isNaN(+q)) state.phase = +q;
function save() {
try { localStorage.setItem(key, JSON.stringify(state)); } catch (e) {}
}
function tagClass(t) {
if (t === 'done') return 'done';
if (t === 'now') return 'now';
if (t === 'park') return 'park';
return 'plan';
}
function renderPhases() {
list.innerHTML = '';
PHASES.forEach(function (p) {
var el = document.createElement('div');
el.className = 'phase' + (state.phase === p.n ? ' active' : '');
el.innerHTML = '<div class="top"><span class="num">Phase ' + p.n + ' · ' + p.title + '</span><span class="tag ' + tagClass(p.tag) + '">' + p.tag + '</span></div><p>' + p.blurb + '</p>';
el.onclick = function () {
state.phase = p.n;
save();
renderPhases();
syncHud();
history.replaceState(null, '', '?phase=' + p.n);
};
list.appendChild(el);
});
}
function syncHud() {
var p = PHASES.filter(function (x) { return x.n === state.phase; })[0];
hud.textContent = 'Muse Glimmer · Phase Lab · focus P' + state.phase + (p ? ' · ' + p.title : '');
banner.textContent = 'Focus Phase ' + state.phase + (p ? ' — ' + p.title + '. ' + p.blurb : '');
}
document.querySelectorAll('#look-checks input').forEach(function (inp) {
var k = inp.getAttribute('data-k');
inp.checked = !!state.checks[k];
inp.onchange = function () {
state.checks[k] = inp.checked;
save();
};
});
document.getElementById('btn-credit').onclick = function () {
var c = document.getElementById('credit');
c.classList.add('show');
setTimeout(function () { c.classList.remove('show'); }, 2200);
};
document.getElementById('btn-config').onclick = function () { if (window.E29Panel) window.E29Panel.open(); };
function renderLookButtons() {
var box = document.getElementById('look-buttons');
if (!box || !window.MuseLooks) return;
box.innerHTML = '';
window.MuseLooks.list().forEach(function (l) {
var b = document.createElement('button');
b.type = 'button';
b.className = 'btn' + (window.MuseLooks.active() === l.id ? '' : ' secondary');
b.textContent = 'Look ' + l.id + ' · ' + l.name;
b.onclick = function () { window.MuseLooks.setActive(l.id); };
box.appendChild(b);
});
}
window.addEventListener('load', function () {
renderLookButtons();
if (window.MuseLooks && window.MuseLooks.onChange) window.MuseLooks.onChange(renderLookButtons);
});
document.getElementById('btn-focus').onclick = function () {
document.getElementById('muse-canvas').focus();
document.getElementById('muse-canvas').click();
};
// [e30] sidebar hide / show (H). The crosshair follows the game view either way.
function setSide(hidden) { document.body.classList.toggle('noside', !!hidden); try { localStorage.setItem('muse-engine-30.noside', hidden ? '1' : '0'); } catch (e) {} window.dispatchEvent(new Event('resize')); }
document.getElementById('btn-side').onclick = function () { setSide(true); };
document.getElementById('e30-side-toggle').onclick = function () { setSide(false); };
window.addEventListener('keydown', function (e) {
if (e.code !== 'KeyH' || (e.target && /^(INPUT|TEXTAREA|SELECT)$/.test(e.target.tagName))) return;
if (window.MuseEngine29 && window.MuseEngine29.isBlocked && window.MuseEngine29.isBlocked()) return;
setSide(!document.body.classList.contains('noside'));
});
try { if (localStorage.getItem('muse-engine-30.noside') === '1') document.body.classList.add('noside'); } catch (e) {}
window.E30Side = { set: setSide, hidden: function () { return document.body.classList.contains('noside'); } };
renderPhases();
syncHud();
})();
</script>
<script src="engine/looks/look-switcher.js?v=e30"></script>
<script src="game/looks/look-a.js?v=e30"></script>
<script src="game/looks/look-b.js?v=e30"></script>
<script src="engine/import/scene-units.js?v=e32-rc-1"></script>
<script src="engine/physics/mesh-collider.js?v=e30"></script>
<script src="engine/anim/clip-map.js?v=e31"></script>
<script src="engine/anim/capsule-fit.js?v=e31"></script>
<script src="engine/anim/skeleton-pose.js?v=e31"></script>
<script src="engine/anim/bone-budget.js?v=e31"></script>
<script src="engine/check/model-check.js?v=e32-rc-1"></script>
<script src="engine/check/texture-budget.js?v=e32-rc-1"></script>
<script src="engine/anim/root-motion.js?v=e32-rc-1"></script>
<script src="engine/io/setup-schema.js?v=e32-rc-1"></script>
<script src="engine/engine.js?v=e32-rc-1"></script>
<script src="engine/ui/start-screen.js?v=e31"></script>
<script src="engine/ui/config-panel.js?v=e32-rc-1"></script>
<script src="engine/ui/e32-ui.js?v=e32-rc-1"></script>
</body>
</html>