feat(about): implement 90-degree orthogonal isometric river with large-screen overflow and responsive timeline
This commit is contained in:
@@ -12,16 +12,15 @@ import {
|
||||
} from './scenePrimitives';
|
||||
import styles from './Scenes.module.css';
|
||||
|
||||
// Sharp 90-degree orthogonal isometric river path:
|
||||
// Enters from bottom-left along the isometric Z axis,
|
||||
// takes a sharp 90-degree orthogonal step across the isometric X axis at the center,
|
||||
// and turns 90 degrees to continue along the isometric Z axis towards the top-right.
|
||||
const riverPath = [
|
||||
new THREE.Vector2(4.5, -13),
|
||||
new THREE.Vector2(2.1, -7.4),
|
||||
new THREE.Vector2(0.2, -3.8),
|
||||
new THREE.Vector2(0.2, -1.2),
|
||||
new THREE.Vector2(1.5, 0.2),
|
||||
new THREE.Vector2(-0.8, 2.4),
|
||||
new THREE.Vector2(-0.1, 4.1),
|
||||
new THREE.Vector2(-2.5, 8.1),
|
||||
new THREE.Vector2(-3.3, 13),
|
||||
new THREE.Vector2(-1.3, -16),
|
||||
new THREE.Vector2(-1.3, 0),
|
||||
new THREE.Vector2(1.3, 0),
|
||||
new THREE.Vector2(1.3, 16),
|
||||
];
|
||||
|
||||
const createAboutScene: SceneFactory = ({ pointer, theme, reduceMotion }) => {
|
||||
@@ -42,7 +41,7 @@ const createAboutScene: SceneFactory = ({ pointer, theme, reduceMotion }) => {
|
||||
});
|
||||
|
||||
const ground = new THREE.Mesh(
|
||||
new THREE.PlaneGeometry(34, 34),
|
||||
new THREE.PlaneGeometry(60, 60),
|
||||
new THREE.MeshStandardMaterial({ color: palette.ground, roughness: 1 }),
|
||||
);
|
||||
ground.rotation.x = -Math.PI / 2;
|
||||
@@ -51,9 +50,9 @@ const createAboutScene: SceneFactory = ({ pointer, theme, reduceMotion }) => {
|
||||
world.add(ground);
|
||||
|
||||
const gridVertices: number[] = [];
|
||||
for (let value = -17; value <= 17; value += 1) {
|
||||
gridVertices.push(-17, -0.3, value, 17, -0.3, value);
|
||||
gridVertices.push(value, -0.3, -17, value, -0.3, 17);
|
||||
for (let value = -30; value <= 30; value += 1) {
|
||||
gridVertices.push(-30, -0.3, value, 30, -0.3, value);
|
||||
gridVertices.push(value, -0.3, -30, value, -0.3, 30);
|
||||
}
|
||||
const gridGeometry = new THREE.BufferGeometry();
|
||||
gridGeometry.setAttribute('position', new THREE.Float32BufferAttribute(gridVertices, 3));
|
||||
@@ -96,8 +95,8 @@ const createAboutScene: SceneFactory = ({ pointer, theme, reduceMotion }) => {
|
||||
world.add(primaryPlates, secondaryPlates, tertiaryPlates);
|
||||
|
||||
[
|
||||
[-7.5, -7.7, 9.5, 5.1], [-6.2, -2.7, 8.5, 4.2], [-6.5, 2.2, 8.7, 4.3],
|
||||
[-7.1, 7.2, 9.2, 5.0], [7.4, -8.0, 9.4, 5.4], [6.2, -2.9, 8.0, 4.1],
|
||||
[-7.5, -7.7, 9.5, 5.1], [-6.6, -2.7, 8.5, 4.2], [-6.8, 2.2, 8.7, 4.3],
|
||||
[-7.1, 7.2, 9.2, 5.0], [7.4, -8.0, 9.4, 5.4], [6.4, -2.9, 8.0, 4.1],
|
||||
[6.6, 2.0, 8.4, 4.2], [6.3, 7.0, 9.1, 5.0],
|
||||
].forEach(([x, z, width, depth]) => addPlate(primaryPlates, x, z, width, depth));
|
||||
|
||||
@@ -108,7 +107,7 @@ const createAboutScene: SceneFactory = ({ pointer, theme, reduceMotion }) => {
|
||||
addPlate(secondaryPlates, x, z, width, depth, 0.5, theme === 'dark' ? 0x0b2f5f : 0xe6f0fe),
|
||||
);
|
||||
|
||||
const riverGeometry = new THREE.ShapeGeometry(createRibbonShape(riverPath, 2.2));
|
||||
const riverGeometry = new THREE.ShapeGeometry(createRibbonShape(riverPath, 1.8));
|
||||
const waterMaterial = new THREE.MeshStandardMaterial({
|
||||
color: palette.water,
|
||||
emissive: palette.water,
|
||||
@@ -130,15 +129,15 @@ const createAboutScene: SceneFactory = ({ pointer, theme, reduceMotion }) => {
|
||||
const direction = end.clone().sub(start);
|
||||
const length = direction.length();
|
||||
direction.normalize();
|
||||
for (let distance = 1; distance < length; distance += 1.15) {
|
||||
for (let distance = 1.3; distance < length - 0.7; distance += 1.35) {
|
||||
const at = start.clone().addScaledVector(direction, distance);
|
||||
const seam = new THREE.Mesh(
|
||||
new THREE.PlaneGeometry(2.08, 0.014),
|
||||
new THREE.MeshBasicMaterial({ color: palette.edge, transparent: true, opacity: 0.35 }),
|
||||
new THREE.PlaneGeometry(1.72, 0.016),
|
||||
new THREE.MeshBasicMaterial({ color: palette.edge, transparent: true, opacity: 0.32 }),
|
||||
);
|
||||
seam.rotation.x = -Math.PI / 2;
|
||||
seam.rotation.z = Math.atan2(direction.y, direction.x) + Math.PI / 2;
|
||||
seam.position.set(at.x, -0.2, at.y);
|
||||
seam.position.set(at.x, -0.21, -at.y);
|
||||
tertiaryPlates.add(seam);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user