Add zoom, pan, and camera reset to 3D editors

Enable zoom (scroll/pinch) and pan (right-click/two-finger drag) on
all OrbitControls. Add resetView() to BaseRenderer that restores
initial camera state and auto-rotate via OrbitControls.saveState/reset.
Add reset camera button to EditorTooltip with mobile-friendly touch
targets and hover-only highlight to avoid sticky state on touch.
This commit is contained in:
Christian Semmler 2026-02-13 17:11:25 -08:00
parent 57b1c31305
commit cf23e22931
6 changed files with 74 additions and 9 deletions

View File

@ -96,6 +96,7 @@ export class ActorRenderer extends BaseRenderer {
this.setupControls(new THREE.Vector3(0, 0.2, 0));
this.controls.autoRotate = false;
this._initialAutoRotate = false;
this.raycaster = new THREE.Raycaster();
}

View File

@ -41,8 +41,8 @@ export class BaseRenderer {
setupControls(target) {
this.controls = new OrbitControls(this.camera, this.canvas);
this.controls.enableZoom = false;
this.controls.enablePan = false;
this.controls.enableZoom = true;
this.controls.enablePan = true;
this.controls.enableDamping = true;
this.controls.dampingFactor = 0.1;
this.controls.autoRotate = true;
@ -66,6 +66,15 @@ export class BaseRenderer {
this.canvas.addEventListener('pointerdown', this._onPointerDown);
this.canvas.addEventListener('pointermove', this._onPointerMove);
this._initialAutoRotate = this.controls.autoRotate;
this.controls.saveState();
}
resetView() {
if (!this.controls) return;
this.controls.reset();
this.controls.autoRotate = this._initialAutoRotate;
}
wasDragged() {

View File

@ -1,11 +1,26 @@
<script>
export let text = '';
export let onResetCamera = null;
</script>
<div class="editor-tooltip-wrapper">
<div class="tooltip-icons">
{#if onResetCamera}
<button
type="button"
class="reset-camera-btn"
onclick={onResetCamera}
title="Reset camera"
>
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor">
<path d="M8 1a7 7 0 0 0-7 7h2a5 5 0 0 1 9.17-2.74L10 7h5V2l-1.87 1.87A7 7 0 0 0 8 1z"/>
</svg>
</button>
{/if}
<span class="tooltip-trigger">?
<span class="tooltip-content">{text}</span>
</span>
</div>
<div class="editor-tooltip-content">
<slot />
</div>
@ -17,11 +32,51 @@
width: 100%;
}
.tooltip-trigger {
.tooltip-icons {
position: absolute;
top: 0;
right: 0;
z-index: 1;
display: flex;
align-items: center;
gap: 8px;
}
.reset-camera-btn {
position: relative;
width: 16px;
height: 16px;
border-radius: 50%;
background-color: var(--color-border-medium);
color: #eee;
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
padding: 0;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
/* Expand touch target on mobile */
@media (pointer: coarse) {
.reset-camera-btn::before {
content: '';
position: absolute;
inset: -10px;
}
}
@media (hover: hover) {
.reset-camera-btn:hover {
background-color: var(--color-primary);
color: var(--color-bg-panel);
}
}
.reset-camera-btn:active {
background-color: var(--color-primary);
color: var(--color-bg-panel);
}
.editor-tooltip-content {

View File

@ -333,7 +333,7 @@
}
</script>
<EditorTooltip text="Click to customize based on your current character. Navigate between all 66 game actors using the arrows. Changes are automatically saved.">
<EditorTooltip text="Click to customize based on your current character. Navigate between all 66 game actors using the arrows. Changes are automatically saved." onResetCamera={() => renderer?.resetView()}>
<div class="preview-container">
<canvas
bind:this={canvas}

View File

@ -122,7 +122,7 @@
}
</script>
<EditorTooltip text="Click on the cube to cycle high scores. Changes are automatically saved.">
<EditorTooltip text="Click on the cube to cycle high scores. Changes are automatically saved." onResetCamera={() => renderer?.resetView()}>
<div class="score-cube-container">
<canvas
bind:this={canvas}

View File

@ -323,7 +323,7 @@
</script>
<EditorTooltip text="Click on the part to cycle through colors. Use the texture button to customize textures on supported parts (vehicle must be fully built first). Changes are automatically saved.">
<EditorTooltip text="Click on the part to cycle through colors. Use the texture button to customize textures on supported parts (vehicle must be fully built first). Changes are automatically saved." onResetCamera={() => renderer?.resetView()}>
<!-- 3D Preview (clickable to cycle color) -->
<div class="preview-container">
<canvas