feat(n7web): add pet NFC workflow and glass UI

This commit is contained in:
Miayui
2026-09-14 15:16:02 +08:00
parent 812e67422d
commit aa6f59d3a6
20 changed files with 2724 additions and 102 deletions
+45 -43
View File
@@ -1643,37 +1643,37 @@ function createTwinCabin(THREE, scene) {
const TWIN_THEME_PALETTES = {
user: {
accent: 0x2f80ed,
accentStrong: 0x1d5fbf,
accentSoft: 0xdbeeff,
sceneBackground: 0xeff6ff,
floor: 0xe5f0fd,
gridStrong: 0x75a9e8,
gridSoft: 0xc7daf2,
fillLight: 0xb7d9ff,
vehicleBody: 0x91c6f5,
vehicleDetail: 0x77a9d8,
vehicleInterior: 0x4d79a6,
vehicleTrim: 0x284c70,
vehicleMetal: 0x93b9da,
vehicleOutline: 0x2879d8,
vehicleOccluded: 0x9abbdc,
seatShell: 0x2b76c9,
seatInsert: 0xcfe7ff,
seatThermal: 0x72b5f5,
seatBolster: 0x1b5fae,
seatStructure: 0x25476e,
seatEdge: 0x69b4ff,
seatSeam: 0xe4f2ff,
glass: 0x4b9bea,
glassEmissive: 0x164f91,
glassEdge: 0x1b6fc4,
accent: 0x7b70f5,
accentStrong: 0x5d4dd9,
accentSoft: 0x9ba8ff,
sceneBackground: 0x111426,
floor: 0x1a2038,
gridStrong: 0x758cff,
gridSoft: 0x3c496d,
fillLight: 0x93b4ff,
vehicleBody: 0x729bc9,
vehicleDetail: 0x557da8,
vehicleInterior: 0x344f72,
vehicleTrim: 0x1a2943,
vehicleMetal: 0x7896b5,
vehicleOutline: 0x73b8ff,
vehicleOccluded: 0x526583,
seatShell: 0x426fbd,
seatInsert: 0xa9c8ea,
seatThermal: 0x65a9ed,
seatBolster: 0x295694,
seatStructure: 0x263b5e,
seatEdge: 0x76bdff,
seatSeam: 0xcbe4ff,
glass: 0x4d8ed2,
glassEmissive: 0x183f76,
glassEdge: 0x397ac0,
glassGlow: 0x79c7ff,
roofClear: 0x67aef4,
roofDark: 0x183b70,
lamp: 0x2e7fd4,
lampEmissive: 0x48a4f2,
lampEdge: 0x1e6bb8,
roofClear: 0x649cda,
roofDark: 0x1d315c,
lamp: 0x4385cf,
lampEmissive: 0x55acf4,
lampEdge: 0x3476b9,
},
};
@@ -1695,8 +1695,9 @@ function createTwinGroundTexture(THREE, palette, size = 768) {
const context = textureCanvas.getContext("2d");
if (!context) return null;
const accent = new THREE.Color(palette.accent);
const gridColor = accent.clone().lerp(new THREE.Color(0xffffff), 0.52);
const floorColor = new THREE.Color(palette.floor);
const gridStrong = new THREE.Color(palette.gridStrong);
const gridSoft = new THREE.Color(palette.gridSoft);
const rgba = (color, alpha) => {
const red = Math.round(color.r * 255);
const green = Math.round(color.g * 255);
@@ -1704,8 +1705,8 @@ function createTwinGroundTexture(THREE, palette, size = 768) {
return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
};
const center = size / 2;
// The white base is fully opaque beneath the vehicle and fades to completely
// transparent at the outer edge. Theme colors are reserved for the grid.
// Keep the ground dark and translucent so it reads as another layer of the
// glass workspace instead of a white rectangle inside the themed shell.
const outerRadius = size * 0.48;
context.clearRect(0, 0, size, size);
@@ -1717,11 +1718,11 @@ function createTwinGroundTexture(THREE, palette, size = 768) {
center,
outerRadius,
);
surfaceGradient.addColorStop(0, "rgba(255, 255, 255, 1)");
surfaceGradient.addColorStop(0.18, "rgba(255, 255, 255, 1)");
surfaceGradient.addColorStop(0.48, "rgba(255, 255, 255, 0.72)");
surfaceGradient.addColorStop(0.75, "rgba(255, 255, 255, 0.28)");
surfaceGradient.addColorStop(1, "rgba(255, 255, 255, 0)");
surfaceGradient.addColorStop(0, rgba(floorColor, 0.96));
surfaceGradient.addColorStop(0.2, rgba(floorColor, 0.9));
surfaceGradient.addColorStop(0.52, rgba(floorColor, 0.58));
surfaceGradient.addColorStop(0.78, rgba(floorColor, 0.2));
surfaceGradient.addColorStop(1, rgba(floorColor, 0));
context.fillStyle = surfaceGradient;
context.fillRect(0, 0, size, size);
@@ -1733,7 +1734,7 @@ function createTwinGroundTexture(THREE, palette, size = 768) {
for (let index = 0; index <= 40; index += 1) {
const position = index * gridStep;
const major = index % 5 === 0;
gridContext.strokeStyle = rgba(gridColor, major ? 0.32 : 0.16);
gridContext.strokeStyle = rgba(major ? gridStrong : gridSoft, major ? 0.38 : 0.24);
gridContext.lineWidth = major ? 0.9 : 0.45;
gridContext.beginPath();
gridContext.moveTo(position, 0);
@@ -3944,8 +3945,9 @@ function initSeatTwin() {
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xeff6ff);
scene.fog = new THREE.Fog(0xeff6ff, 12, 19);
const twinPalette = TWIN_THEME_PALETTES.user;
scene.background = new THREE.Color(twinPalette.sceneBackground);
scene.fog = new THREE.Fog(twinPalette.sceneBackground, 12, 19);
const camera = new THREE.PerspectiveCamera(34, 1, 0.1, 40);
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x7d8b90, 2.2);
hemisphereLight.layers.enable(1);
@@ -3960,7 +3962,7 @@ function initSeatTwin() {
keyLight.shadow.camera.top = 6;
keyLight.shadow.camera.bottom = -4;
scene.add(keyLight);
const fillLight = new THREE.DirectionalLight(0xb7d9ff, 1.15);
const fillLight = new THREE.DirectionalLight(twinPalette.fillLight, 1.15);
fillLight.layers.enable(1);
fillLight.position.set(5, 3, -5);
scene.add(fillLight);