Gate 1.5 -- the round trip. a.test drives the editor's OWN placement function (placeEntry, exported for exactly this) through template -> place -> export -> parse -> validateSite -> createWorld -> dress, then asserts the GLB-backed anchors ADOPTED and the carport's 0.22/0.30 came out the far side. Mutation-checked with five deliberate breakages; four went red and ONE DID NOT -- the key-order test shuffled only root keys, every one of which is in KEY_ORDER, so the alphabetical fallback it claimed to protect was never reached. Rewritten around unknown keys, re-mutated, red in both halves. A determinism test that passed while testing nothing. Picking bug, found by dispatching real PointerEvents rather than reading the code: clicking an object's FOOT selected nothing, because the pick handle is a cylinder centred 1.7 m up and from a raised camera the ray has already run ~2 m horizontally by the time it climbs there. pickRef now falls back to nearest-placed-thing within 1.3 m of the ground hit -- camera-angle independent, so it can't rot when the pitch changes. Phantom sail (pool, filed unlanded in S13) -- LANDED and negative-controlled. Teardown factored into disposeSailView() and called from loadSiteInto before refreshCameraSolids (which reads sailView and would re-register a disposed mesh as a camera collider). Rig state goes with the view. Verified through the real game both ways: with the fix removed the cloth still hangs over the corner block, screenshotted. Dev-line (pool) -- two findings, both landed. The line counted `pieces` only, so it read "debris 0" while seven leaves flew; now reports both populations off C's leafCount. And index.html's boot-failure handler wrote into #dev, which is display:none off localhost -- so a failed boot on partly.party showed a stranger a blank page. It has its own visible #fatal element now. E's gap 2, runtime half -- and it was worse than "one click away": nextId namespaces structures s1, s2..., so the FIRST carport the editor places was already free. collateralFor/wreckStructure/isWrecked now resolve through structKey (site collateralKey, then GLB collateral_key, then id last so every existing site is untouched). Negative-controlled: id-equality prices an editor carport to null. E's tie_off:false honoured at both ends. E's swing set and jacaranda are in the palette behind a `requires` gate, so they switch themselves on when the ANCHOR_TYPE widening merges. Also: `return t.skip(msg)` is a fake pass -- Suite.skip pushes a new result and lets the current test record as pass. a.test had six; all converted to the documented 'SKIPPED --' idiom. Selftest 373/0/0, no skips. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
81 lines
3.6 KiB
HTML
81 lines
3.6 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>HARD YARDS — rig it, then survive the night</title>
|
|
<style>
|
|
html, body { margin: 0; height: 100%; overflow: hidden; background: #9fc4dd; }
|
|
canvas { display: block; width: 100%; height: 100%; }
|
|
#dev, #help {
|
|
position: fixed; left: 10px;
|
|
font: 12px ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
color: #eef4f8; text-shadow: 0 1px 2px #0009;
|
|
pointer-events: none; user-select: none;
|
|
}
|
|
/* SPRINT13 gate 3 — the dev line moved out from under Lane B's anchor panel
|
|
(top:12/left:12; this was top:10/left:10, so they typeset on top of each
|
|
other all sprint — QA snag list). Top-RIGHT now, and hidden unless asked
|
|
for: see main.js's dev-line block. A stranger on partly.party was reading
|
|
"60 fps · storm 12.3s · debris 4" on the front door of a public game, which
|
|
is a dev build talking to someone who came to play. */
|
|
#dev { top: 10px; right: 10px; left: auto; text-align: right; display: none; }
|
|
#dev.on { display: block; }
|
|
#help { bottom: 10px; opacity: .75; }
|
|
/* SPRINT14 pool — the boot failure used to be written into #dev, which is
|
|
display:none off localhost. So on partly.party a failed boot showed a
|
|
stranger a blank blue page and put the only explanation on a console they
|
|
will never open. A fatal error is not dev chatter: it is the one message
|
|
that must reach the person who came to play, so it gets its own element
|
|
that is visible by default and reads like a sentence rather than a
|
|
readout. */
|
|
#fatal {
|
|
position: fixed; inset: 0; display: none; place-content: center;
|
|
padding: 32px; text-align: center; background: #10161b; color: #ffd9d6;
|
|
font: 15px/1.7 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
}
|
|
#fatal.on { display: grid; }
|
|
#fatal b { display: block; font-size: 13px; letter-spacing: .16em; color: #ff8f86; margin-bottom: 12px; }
|
|
#fatal span { display: block; font-size: 12px; opacity: .7; margin-top: 14px; }
|
|
#banner {
|
|
position: fixed; top: 38%; left: 0; right: 0;
|
|
text-align: center; pointer-events: none; user-select: none;
|
|
font: 700 42px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
letter-spacing: .18em; color: #fff; text-shadow: 0 2px 12px #0007;
|
|
opacity: 0; transition: opacity .45s ease;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<canvas id="c"></canvas>
|
|
<div id="banner"></div>
|
|
<div id="dev">booting…</div>
|
|
<div id="fatal"></div>
|
|
|
|
<script type="importmap">
|
|
{ "imports": { "three": "./vendor/three.module.js",
|
|
"three/addons/": "./vendor/addons/" } }
|
|
</script>
|
|
<script type="module">
|
|
import { boot } from './js/main.js';
|
|
// boot() is async now — it fetches two storm defs, the ped, the clip pack
|
|
// and Lane E's debris GLBs. Surface a failure on the page rather than
|
|
// letting it die as an unhandled rejection behind a blue screen.
|
|
boot().catch((err) => {
|
|
console.error(err);
|
|
// Into #fatal, NOT #dev: #dev is display:none off localhost, so this
|
|
// message has been invisible to every stranger it was written for.
|
|
const box = document.getElementById('fatal');
|
|
box.innerHTML = '<div><b>HARD YARDS COULDN\'T START</b></div>';
|
|
box.firstChild.append(
|
|
Object.assign(document.createElement('div'), { textContent: err.message }),
|
|
Object.assign(document.createElement('span'), {
|
|
textContent: 'A reload usually fixes it. If it doesn\'t, the details are in the browser console.',
|
|
}),
|
|
);
|
|
box.classList.add('on');
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|