Documentation Index
Fetch the complete documentation index at: https://mintlify.com/liltrendi/gitlantis/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Gitlantis provides two navigation aids to help you orient yourself in the 3D ocean world: an overhead minimap and a directional compass.
Minimap
The minimap renders a top-down orthographic view of the world, centered on your boat.
Minimap Modes
Standard Mode
Fullscreen Mode
In standard mode, the minimap appears as a small overlay in the bottom-right corner:
- Size: 120x120 pixels
- Position: 10px from bottom-right corner
- Zoom level: 3.5x
- Toggle: Press
F to switch to fullscreen
const minimapSize = { width: 120, height: 120 };
const minimapPosition = {
x: size.width - minimapSize.width - 10,
y: size.height - minimapSize.height - 10,
};
Source: src/browser/hooks/useMinimap/index.ts:18-30 Press F to toggle fullscreen mode:
- Size: Entire viewport
- Position: Centered
- Zoom level: 0.8x (wider view)
- Boat scale: 2x larger for visibility
const minimapSize = isMinimapFullScreen
? { width: size.width, height: size.height }
: { width: 120, height: 120 };
Source: src/browser/hooks/useMinimap/index.ts:18-20
Camera Implementation
The minimap uses a virtual orthographic camera that tracks the boat from above:
const targetPos = boatRef.current.position;
virtualCam.current.position.set(targetPos.x, targetPos.y + 50, targetPos.z);
virtualCam.current.lookAt(targetPos);
virtualCam.current.rotateZ(Math.PI / 2);
The camera is positioned 50 units above the boat and rotated 90° to align north upward.
Source: src/browser/hooks/useMinimap/index.ts:36-39
Rendering Pipeline
The minimap uses WebGL scissor testing to render a separate viewport:
gl.autoClear = false;
gl.clearDepth();
gl.setScissorTest(true);
gl.setViewport(
minimapPosition.x,
minimapPosition.y,
minimapSize.width,
minimapSize.height
);
gl.setScissor(
minimapPosition.x,
minimapPosition.y,
minimapSize.width,
minimapSize.height
);
gl.render(scene, virtualCam.current);
gl.setScissorTest(false);
gl.setViewport(0, 0, size.width, size.height);
This technique allows rendering the same scene from two different cameras simultaneously.
Source: src/browser/hooks/useMinimap/index.ts:42-61
Interactive Minimap
You can click on the minimap to open files and folders:
function onClick(event: MouseEvent) {
const { clientX, clientY } = event;
const inside =
clientX >= minimapPosition.x &&
clientX <= minimapPosition.x + minimapSize.width &&
clientY >= minimapPosition.y &&
clientY <= minimapPosition.y + minimapSize.height;
if (!inside || !virtualCam.current) return;
pointer.x = ((clientX - minimapPosition.x) / minimapSize.width) * 2 - 1;
pointer.y = -((clientY - minimapPosition.y) / minimapSize.height) * 2 + 1;
raycaster.setFromCamera(pointer, virtualCam.current);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length) {
const object = intersects[0].object;
object.userData?.openOnClick();
}
}
The system:
- Checks if the click is within minimap bounds
- Converts screen coordinates to normalized device coordinates
- Uses raycasting to detect which object was clicked
- Calls the object’s
openOnClick handler
Source: src/browser/hooks/useMinimap/index.ts:84-104
Visibility Settings
The minimap respects user settings and can be hidden:
if (!virtualCam.current || !boatRef?.current || settings.minimap === "Hide")
return;
Source: src/browser/hooks/useMinimap/index.ts:33
Compass
The compass displays your current heading using cardinal directions and degrees.
Heading Calculation
The compass extracts the boat’s yaw rotation and converts it to degrees:
const yawRadians = new Euler().setFromQuaternion(
boatRef.current.quaternion,
"YXZ"
).y;
let yawDegrees = -(yawRadians * (180 / Math.PI));
yawDegrees = ((yawDegrees % 360) + 360) % 360;
The rotation is normalized to 0-360° and updated every 16ms (60fps).
Source: src/browser/hooks/useBoat/compass/index.ts:12-18
Cardinal Directions
The compass supports 8 cardinal directions:
Cardinal Points
Closest Cardinal
const cardinals = [
{ label: "N", degree: 0 },
{ label: "NE", degree: 45 },
{ label: "E", degree: 90 },
{ label: "SE", degree: 135 },
{ label: "S", degree: 180 },
{ label: "SW", degree: 225 },
{ label: "W", degree: 270 },
{ label: "NW", degree: 315 },
];
Source: src/browser/hooks/useBoat/compass/index.ts:24-33The system finds the closest cardinal direction to your current heading:const getClosestCardinal = (degree: number) => {
const normalizedDegree = ((degree % 360) + 360) % 360;
let closestDirection = "";
let minDifference = Infinity;
for (const point of cardinals) {
let difference = Math.abs(normalizedDegree - point.degree);
if (difference > 180) {
difference = 360 - difference;
}
if (difference < minDifference) {
minDifference = difference;
closestDirection = point.label;
}
}
return closestDirection;
};
This handles the wrap-around at 360°/0° correctly.Source: src/browser/hooks/useBoat/compass/index.ts:35-54
The compass creates a scrollable strip of cardinal points:
const createScrollableCompass = () => {
const strip: Array<{ label: string; degree: number; key: string }> = [];
for (let circle = -2; circle <= 2; circle++) {
cardinals.forEach((cardinal) => {
const adjustedDegree = cardinal.degree + circle * 360;
strip.push({
...cardinal,
degree: adjustedDegree,
key: `${cardinal.label}-${circle}`,
});
});
}
return strip.sort((a, b) => a.degree - b.degree);
};
This creates 5 full rotations (-2 to +2 circles) for smooth infinite scrolling.
Source: src/browser/hooks/useBoat/compass/index.ts:56-69
The compass displays both numeric degrees and the nearest cardinal direction:const degreesLabel = `${Math.round(currentRotation) ?? 0}° ${
getClosestCardinal(Math.round(currentRotation)) ?? ""
}`;
Example: 347° NW or 90° ESource: src/browser/hooks/useBoat/compass/index.ts:75-77
Both navigation aids are designed for minimal performance impact:
- Minimap: Uses scissor testing to avoid separate render passes
- Compass: Updates at 60fps but only recalculates when rotation changes
- Fade-in: Both components respect the splash screen state and fade in after 1700ms
const [shouldFadeIn, setShouldFadeIn] = useState(
settings.minimap === "Show" && !showSplashScreen
);
useEffect(() => {
if (settings.minimap === "Show" && !showSplashScreen) {
setTimeout(() => setShouldFadeIn(true), 1700);
}
}, [settings.minimap, showSplashScreen]);
Source: src/browser/components/world/minimap/index.tsx:12-20