add 3d to srebot (#1350)

This commit is contained in:
NotSoToothless
2026-06-21 07:54:35 -07:00
committed by GitHub
parent 28a635438d
commit 8a084fb644
9 changed files with 37226 additions and 6 deletions
+61 -1
View File
@@ -488,6 +488,18 @@
align-items: center;
min-width: 0;
}
.rc-stage {
position: relative;
width: 100%;
aspect-ratio: 1 / 1;
}
.rc-stage .rc-canvas,
.rc-stage .rc-3d-container {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.rc-canvas {
width: 100%;
height: auto;
@@ -496,6 +508,23 @@
cursor: crosshair;
border: 1px solid rgba(255,255,255,0.06);
}
.rc-3d-container {
border-radius: 0.4rem;
overflow: hidden;
background: #0b0d10;
border: 1px solid rgba(255,255,255,0.06);
}
.rc-3d-container canvas {
display: block;
width: 100%;
height: 100%;
cursor: grab;
}
.rc-hidden { display: none !important; }
.rc-mode-btn-disabled {
opacity: 0.35;
cursor: not-allowed;
}
.rc-tickets {
display: flex;
align-items: center;
@@ -695,6 +724,10 @@
<button class="rc-mode-btn active" data-mode="ground" onclick="switchReplayMode('ground')"><i class="fas fa-crosshairs" style="margin-right: 4px;"></i><%= t('games.modeGround') %></button>
<button class="rc-mode-btn" data-mode="air" onclick="switchReplayMode('air')"><i class="fas fa-plane" style="margin-right: 4px;"></i><%= t('games.modeAir') %></button>
</div>
<div class="rc-mode-toggle" id="rcViewToggle" onclick="event.stopPropagation()">
<button class="rc-mode-btn active" data-view="2d" onclick="switchReplayView('2d')">2D</button>
<button class="rc-mode-btn" data-view="3d" onclick="switchReplayView('3d')">3D</button>
</div>
<i class="fas fa-chevron-down" id="replayViewerToggleIcon"></i>
</div>
<div class="log-body" id="replayViewerBody" style="max-height: none; padding: 1rem; font-family: inherit;">
@@ -749,6 +782,15 @@
<script src="/js/api-client.js?v=3"></script>
<script src="/js/vehicle-i18n.js"></script>
<script src="/js/header-search.js?v=2"></script>
<script type="importmap">
{
"imports": {
"three": "/vendor/three/three.module.js",
"three/addons/": "/vendor/three/addons/"
}
}
</script>
<script type="module" src="/js/replay-canvas-3d.js?v=1"></script>
<script src="/js/replay-canvas.js?v=15"></script>
<script>
const sessionId = '<%= sessionId %>';
@@ -939,6 +981,15 @@
if (replayViewer.hasAirMode) {
document.getElementById('rcModeToggle').classList.add('visible');
}
// Always show the 2D/3D toggle; dim 3D if unsupported.
const viewToggle = document.getElementById('rcViewToggle');
viewToggle.classList.add('visible');
if (!replayViewer.supports3d) {
const btn3d = viewToggle.querySelector('[data-view="3d"]');
btn3d.disabled = true;
btn3d.classList.add('rc-mode-btn-disabled');
btn3d.title = '3D view not supported on this device';
}
} catch (err) {
loading.style.display = 'block';
loading.innerHTML = '<div class="video-fallback" style="color:#ff6666;">' + (err.message || 'Unknown error') + '</div>';
@@ -948,11 +999,20 @@
function switchReplayMode(mode) {
if (!replayViewer) return;
replayViewer.setMode(mode);
document.querySelectorAll('.rc-mode-btn').forEach(btn => {
document.querySelectorAll('#rcModeToggle .rc-mode-btn').forEach(btn => {
btn.classList.toggle('active', btn.dataset.mode === mode);
});
}
function switchReplayView(view) {
if (!replayViewer) return;
replayViewer.setViewMode(view);
const active = replayViewer._viewMode;
document.querySelectorAll('#rcViewToggle .rc-mode-btn').forEach(btn => {
btn.classList.toggle('active', btn.dataset.view === active);
});
}
function toggleLog(logId) {
const body = document.getElementById(logId + 'Body');
const icon = document.getElementById(logId + 'Icon');