spoint 0.1.691 → 0.1.693
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/client/app.js
CHANGED
|
@@ -3244,6 +3244,11 @@ client.connect().then(async ()=>{
|
|
|
3244
3244
|
const { createMeshDebugPanel } = await import('./hud/MeshDebugPanel.js')
|
|
3245
3245
|
window.__app.meshDebugPanel = createMeshDebugPanel(uiRoot)
|
|
3246
3246
|
}
|
|
3247
|
+
// Optional on-screen render-toggle panel (?debugpanel=1) -- see client/hud/RenderDebugPanel.js.
|
|
3248
|
+
if (_params.has('debugpanel')) {
|
|
3249
|
+
const { createRenderDebugPanel } = await import('./hud/RenderDebugPanel.js')
|
|
3250
|
+
window.__app.renderDebugPanel = createRenderDebugPanel(uiRoot, RenderControls)
|
|
3251
|
+
}
|
|
3247
3252
|
// Joiner side: WireweaveJoinClient.js's connect() (already resolved by the time
|
|
3248
3253
|
// this .then() runs) constructs its own bridge and exposes it on window.__app.wireweave.
|
|
3249
3254
|
// Mount the same room-wide voice widget the host gets below.
|
|
@@ -62,8 +62,14 @@ const PRESETS = {
|
|
|
62
62
|
grassWind: true,
|
|
63
63
|
halfResWater: false,
|
|
64
64
|
thc: false,
|
|
65
|
-
ssao:
|
|
66
|
-
|
|
65
|
+
// ssao/bloom OFF by default on every tier (2026-08-10): live user-witnessed the half-res SSAO
|
|
66
|
+
// upsample producing a persistent dark ground-level smear/ghosting artifact anchored to nearby
|
|
67
|
+
// geometry silhouettes (confirmed via the live ?debugpanel=1 toggle A/B -- disabling ssao alone
|
|
68
|
+
// removed it). Both remain fully wired, live-toggleable RenderControls knobs (window.__renderControls
|
|
69
|
+
// .set('ssao', true) / the debug panel checkbox) for whoever fixes the underlying half-res-upsample
|
|
70
|
+
// artifact next -- this only flips the SHIPPED default, not the feature.
|
|
71
|
+
ssao: false,
|
|
72
|
+
bloom: false,
|
|
67
73
|
ssr: false,
|
|
68
74
|
toneMappingExposure: 1.0,
|
|
69
75
|
},
|
|
@@ -78,8 +84,8 @@ const PRESETS = {
|
|
|
78
84
|
grassWind: true,
|
|
79
85
|
halfResWater: false,
|
|
80
86
|
thc: false,
|
|
81
|
-
ssao:
|
|
82
|
-
bloom:
|
|
87
|
+
ssao: false,
|
|
88
|
+
bloom: false,
|
|
83
89
|
ssr: false,
|
|
84
90
|
toneMappingExposure: 1.0,
|
|
85
91
|
},
|
|
@@ -94,8 +100,8 @@ const PRESETS = {
|
|
|
94
100
|
grassWind: true,
|
|
95
101
|
halfResWater: false,
|
|
96
102
|
thc: false,
|
|
97
|
-
ssao:
|
|
98
|
-
bloom:
|
|
103
|
+
ssao: false,
|
|
104
|
+
bloom: false,
|
|
99
105
|
ssr: true,
|
|
100
106
|
toneMappingExposure: 1.0,
|
|
101
107
|
},
|
|
@@ -412,6 +412,8 @@ const FLAGS = [
|
|
|
412
412
|
doc: 'Join an existing wireweave room (given by ?room=) as a peer, instead of hosting a new one.' },
|
|
413
413
|
{ flag: '?meshdebug', kind: 'query', group: 'networking', readAt: 'client/app.js, client/hud/MeshDebugPanel.js',
|
|
414
414
|
doc: 'Mount a live P2P mesh-topology panel (peer list, connection states, current app-layer host) on top of a ?room= session. window.__meshDebug.list()/.snapshot() are always available regardless of this flag (see client/core/MeshDebug.js) -- this only adds the on-screen visual.' },
|
|
415
|
+
{ flag: '?debugpanel=1', kind: 'query', group: 'render-debug', readAt: 'client/app.js, client/hud/RenderDebugPanel.js',
|
|
416
|
+
doc: 'Mount an on-screen checkbox panel for live A/B-testing render subsystem suspects (sun shadow, SSAO, decal system, grass decals, shadow cascades, player VAT) without console commands -- built for live-tester bisection of visual artifacts.' },
|
|
415
417
|
{ flag: '?netsim=<preset>', kind: 'query', group: 'networking', readAt: 'client/app.js, src/transport/NetworkSimTransport.js',
|
|
416
418
|
doc: 'Transport simulation harness: wraps the real WebSocket/WebTransport connection in NetworkSimTransport, injecting loss/latency/jitter/reorder so netcode is tuned against a real degraded link instead of localhost. Preset names: clean, broadbandGood, wifiTypical, cellular4g, roadmapTarget (150ms/3% loss), degradedWan, brutal (see NETWORK_SIM_PRESETS). Live-retune after connecting via window.__netSim.configure({lossPct,latencyMs,jitterMs,reorderPct}); inspect drop/reorder counts via window.__netSim.getStats().' },
|
|
417
419
|
{ flag: '?world=<name>', kind: 'query', group: 'world', readAt: 'client/app.js',
|
|
@@ -68,7 +68,18 @@ export function createShadowPipeline(sun, opts = {}) {
|
|
|
68
68
|
const scene = opts.scene || sun.parent || null
|
|
69
69
|
const baseExtent = Number.isFinite(opts.extent) ? opts.extent : 60
|
|
70
70
|
const requestedCascades = Number.isFinite(opts.cascades) ? opts.cascades : 1
|
|
71
|
-
|
|
71
|
+
// Cascade 0 IS `sun` (see the loop below) -- if sun.castShadow is false (the documented tree-flicker
|
|
72
|
+
// workaround, SceneSetup.js's sun.castShadow=false), cascade 0's light never renders a shadow map at
|
|
73
|
+
// all, so its shadow.needsUpdate stays true forever and _lastSnapped/target are never placed
|
|
74
|
+
// (_updateCascade's `if (!light.castShadow) return false` early-return, hit every call). A >1 cascade
|
|
75
|
+
// pipeline built on top of that still installs the per-fragment CascadeShadowSelect blend shader,
|
|
76
|
+
// which samples directionalShadowMap[0] -- an uninitialized/never-rendered depth texture -- for every
|
|
77
|
+
// fragment within cascade 0's band (near geometry: the player, close trees, close architecture),
|
|
78
|
+
// producing a visible ghosting/duplication artifact live-witnessed as a real ~2-week-old user-reported
|
|
79
|
+
// bug (2026-08-09). A multi-cascade pipeline is only coherent when every cascade actually renders;
|
|
80
|
+
// clamp to 1 cascade whenever sun.castShadow is off so this file's own multi-cascade code path is
|
|
81
|
+
// never reached with a permanently-dead cascade 0 in it.
|
|
82
|
+
const cascadeCount = sun.castShadow === false ? 1 : Math.max(1, Math.min(MAX_CASCADES, Math.round(requestedCascades)))
|
|
72
83
|
// Sun-from-target offset: DIRECTION is the live light direction, LENGTH places the ortho camera.
|
|
73
84
|
const offset = (opts.offset && opts.offset.isVector3) ? opts.offset.clone() : new THREE.Vector3(40, 80, 30)
|
|
74
85
|
let offsetLen = offset.length()
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Live render-toggle debug panel (?debugpanel=1) -- lets a live tester binary-search a visual
|
|
2
|
+
// artifact by flipping known suspect systems on/off, one at a time, without console commands.
|
|
3
|
+
// Built for the 2026-08-09 shadow/decal-ghosting investigation: every toggle below is a candidate
|
|
4
|
+
// this session ruled in/out by code inspection but could not confirm live (fps-degraded automation
|
|
5
|
+
// tab, screenshot tooling only partially working) -- this panel lets the user do the live A/B
|
|
6
|
+
// themselves and report which toggle changes the artifact.
|
|
7
|
+
|
|
8
|
+
function ensureStyle() {
|
|
9
|
+
if (document.getElementById('render-debug-panel-style')) return
|
|
10
|
+
const s = document.createElement('style')
|
|
11
|
+
s.id = 'render-debug-panel-style'
|
|
12
|
+
s.textContent = `
|
|
13
|
+
.rdp-card{position:fixed;top:max(8px,env(safe-area-inset-top));right:max(8px,env(safe-area-inset-right));z-index:1000;width:min(280px,calc(100vw - 16px));pointer-events:all;display:flex;flex-direction:column;gap:4px;padding:10px;background:rgba(10,12,18,0.92);border:1px solid rgba(255,255,255,0.15);border-radius:8px;font:12px/1.5 ui-monospace,monospace;color:#e6e6e6}
|
|
14
|
+
.rdp-card .rdp-h{font-size:13px;font-weight:600;margin-bottom:4px}
|
|
15
|
+
.rdp-card label{display:flex;align-items:center;gap:6px;cursor:pointer;padding:2px 0}
|
|
16
|
+
.rdp-card input{cursor:pointer}
|
|
17
|
+
`
|
|
18
|
+
document.head.appendChild(s)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Each toggle: label, get() current state, set(bool) apply. Wraps whatever mechanism the target
|
|
22
|
+
// system actually uses (window.__renderControls for registered CONTROLS keys, a raw window.__flag
|
|
23
|
+
// for systems with no RenderControls entry yet).
|
|
24
|
+
function _toggles(renderControls) {
|
|
25
|
+
return [
|
|
26
|
+
{
|
|
27
|
+
label: 'Sun shadow (hostShadowOff)',
|
|
28
|
+
get: () => !(typeof window !== 'undefined' && window.__hostShadowOff),
|
|
29
|
+
set: (on) => { window.__hostShadowOff = !on },
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: 'SSAO',
|
|
33
|
+
get: () => !!renderControls?.get('ssao'),
|
|
34
|
+
set: (on) => renderControls?.set('ssao', on),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
label: 'Decal system (bullet holes/tracers)',
|
|
38
|
+
get: () => !(typeof window !== 'undefined' && window.__decalsOff),
|
|
39
|
+
set: (on) => {
|
|
40
|
+
window.__decalsOff = !on
|
|
41
|
+
const ds = window.__app?.decals
|
|
42
|
+
if (ds && ds._pool) { for (const d of ds._pool) if (d.mesh) d.mesh.visible = on && d.mesh.visible }
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
label: 'Grass decals (scorch/trample overlay)',
|
|
47
|
+
get: () => !(typeof window !== 'undefined' && window.__grassDecalsOff),
|
|
48
|
+
set: (on) => { window.__grassDecalsOff = !on },
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
label: 'Shadow cascades: force to 1',
|
|
52
|
+
get: () => (window.__shadowPipeline?.cascadeCount ?? 1) <= 1,
|
|
53
|
+
set: (on) => {
|
|
54
|
+
if (!on) return
|
|
55
|
+
const sp = window.__shadowPipeline
|
|
56
|
+
if (sp && sp.lights) for (let i = 1; i < sp.lights.length; i++) sp.lights[i].castShadow = false
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
label: 'Player VAT crowd render',
|
|
61
|
+
get: () => !(typeof window !== 'undefined' && window.__playerVatOff),
|
|
62
|
+
set: (on) => { window.__playerVatOff = !on },
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function createRenderDebugPanel(uiRoot, renderControls) {
|
|
68
|
+
ensureStyle()
|
|
69
|
+
const card = document.createElement('div')
|
|
70
|
+
card.className = 'rdp-card'
|
|
71
|
+
uiRoot.appendChild(card)
|
|
72
|
+
|
|
73
|
+
const toggles = _toggles(renderControls)
|
|
74
|
+
const title = document.createElement('div')
|
|
75
|
+
title.className = 'rdp-h'
|
|
76
|
+
title.textContent = 'Render Debug Toggles'
|
|
77
|
+
card.appendChild(title)
|
|
78
|
+
|
|
79
|
+
const hint = document.createElement('div')
|
|
80
|
+
hint.style.cssText = 'color:#999;font-size:11px;margin-bottom:6px'
|
|
81
|
+
hint.textContent = 'Uncheck one at a time to find what causes the ground-mark artifact.'
|
|
82
|
+
card.appendChild(hint)
|
|
83
|
+
|
|
84
|
+
for (const t of toggles) {
|
|
85
|
+
const label = document.createElement('label')
|
|
86
|
+
const input = document.createElement('input')
|
|
87
|
+
input.type = 'checkbox'
|
|
88
|
+
input.checked = t.get()
|
|
89
|
+
input.addEventListener('change', () => t.set(input.checked))
|
|
90
|
+
label.appendChild(input)
|
|
91
|
+
label.appendChild(document.createTextNode(t.label))
|
|
92
|
+
card.appendChild(label)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
node: card,
|
|
97
|
+
destroy() { card.remove() },
|
|
98
|
+
}
|
|
99
|
+
}
|