Walk and fly through the city
Adds walk and fly cameras alongside the helicopter view, switched with 1/2/3 or the city toolbar. Walking uses mouse-look with pointer lock (or drag), WASD, Shift to run and circle-vs-footprint collision with sub-stepping so long frames cannot tunnel through buildings; flying follows the view pitch with Space/C for altitude and clears low roofs. Double-clicking a street drops you there with an animated descent, facing the longest open street. A crosshair names the building ahead (E or click inspects it), the address bar shows the folder you are in, and a minimap shows your heading and teleports on click.
This commit is contained in:
+17
-1
@@ -149,7 +149,7 @@ kbd { font: 500 10px/1.5 var(--mono); border: 1px solid var(--line-strong); bord
|
||||
#glCanvas, #overlayCanvas { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
#overlayCanvas { pointer-events: none; }
|
||||
|
||||
.breadcrumb, .canvas-controls, .camera-help, .legend, .tooltip, .progress-card {
|
||||
.breadcrumb, .canvas-controls, .camera-help, .legend, .tooltip, .progress-card, .city-hud, .city-target, .city-address, .minimap {
|
||||
border: 1px solid var(--line);
|
||||
background: var(--surface);
|
||||
-webkit-backdrop-filter: var(--glass);
|
||||
@@ -275,6 +275,22 @@ kbd { font: 500 10px/1.5 var(--mono); border: 1px solid var(--line-strong); bord
|
||||
.camera-help b { color: var(--muted); font-weight: 600; }
|
||||
@keyframes rise { from { opacity: 0; transform: translateY(4px); } }
|
||||
|
||||
.city-hud { position: absolute; z-index: 2; left: 16px; top: 16px; max-width: calc(100% - 32px); display: flex; flex-wrap: wrap; align-items: center; gap: 12px; padding: 5px 12px 5px 5px; border-radius: 12px; color: var(--dim); font-size: 10.5px; }
|
||||
.city-views { display: flex; gap: 2px; }
|
||||
.city-views button { display: flex; align-items: center; gap: 6px; padding: 5px 10px 5px 6px; border: 1px solid transparent; border-radius: 8px; background: transparent; color: var(--muted); font-size: 11px; font-weight: 500; cursor: pointer; }
|
||||
.city-views button:hover { color: #fff; background: var(--hover); }
|
||||
.city-views button.active { color: #fff; border-color: var(--accent-line); background: var(--accent-soft); }
|
||||
.city-views kbd { padding: 0 4px; font-size: 9px; }
|
||||
.city-help b { color: var(--muted); font-weight: 600; }
|
||||
.crosshair { position: absolute; z-index: 2; left: 50%; top: 50%; width: 18px; height: 18px; margin: -9px 0 0 -9px; pointer-events: none; }
|
||||
.crosshair::before, .crosshair::after { content: ""; position: absolute; background: rgba(255,255,255,.85); box-shadow: 0 0 6px rgba(0,0,0,.8); }
|
||||
.crosshair::before { left: 8px; top: 0; width: 2px; height: 18px; }
|
||||
.crosshair::after { left: 0; top: 8px; width: 18px; height: 2px; }
|
||||
.city-target { position: absolute; z-index: 2; left: 50%; top: calc(50% + 22px); transform: translateX(-50%); padding: 6px 11px; border-radius: 10px; color: #fff; font-weight: 500; white-space: nowrap; pointer-events: none; text-align: center; }
|
||||
.city-target small { display: block; color: var(--muted); font-weight: 400; font-size: 10.5px; }
|
||||
.city-target kbd { margin-left: 6px; }
|
||||
.city-address { position: absolute; z-index: 2; left: 16px; top: 64px; max-width: calc(100% - 32px); padding: 6px 12px; border-radius: 999px; color: var(--text); font: 500 11px var(--mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: none; }
|
||||
.minimap { position: absolute; z-index: 2; right: 16px; bottom: 62px; width: 220px; height: 150px; border-radius: 12px; cursor: crosshair; }
|
||||
.progress-card { position: absolute; z-index: 4; left: 50%; top: 20px; width: min(440px, calc(100% - 30px)); padding: 18px 44px 16px 18px; border-radius: 16px; transform: translateX(-50%); animation: drop .25s ease-out; }
|
||||
@keyframes drop { from { opacity: 0; transform: translate(-50%, -8px); } }
|
||||
.progress-copy { display: flex; flex-direction: column; gap: 3px; }
|
||||
|
||||
Reference in New Issue
Block a user