feat: add GLTF transformation and compression support
- Updated package.json to include @gltf-transform/core, @gltf-transform/extensions, @gltf-transform/functions, and draco3dgltf for GLB file processing. - Implemented GLB compression using Draco in the upload model API route. - Adjusted camera keyframes in ScrollScene for improved animation. - Enhanced overlay styles in ScrollOverlays for better visual clarity. - Added original GLB files for Kandoura, Suit, Unitree_G1, and Vest. - Updated existing GLB files for Kandoura, Suit, Unitree_G1, and Vest.
This commit is contained in:
parent
6dc705b332
commit
83d0d9ab00
2171
package-lock.json
generated
2171
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,9 @@
|
|||||||
"test:watch": "vitest"
|
"test:watch": "vitest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@gltf-transform/core": "^4.3.0",
|
||||||
|
"@gltf-transform/extensions": "^4.3.0",
|
||||||
|
"@gltf-transform/functions": "^4.3.0",
|
||||||
"@libsql/client": "^0.17.2",
|
"@libsql/client": "^0.17.2",
|
||||||
"@prisma/adapter-libsql": "^7.7.0",
|
"@prisma/adapter-libsql": "^7.7.0",
|
||||||
"@prisma/client": "^7.7.0",
|
"@prisma/client": "^7.7.0",
|
||||||
@ -22,6 +25,7 @@
|
|||||||
"@stripe/stripe-js": "^9.1.0",
|
"@stripe/stripe-js": "^9.1.0",
|
||||||
"@types/three": "^0.183.1",
|
"@types/three": "^0.183.1",
|
||||||
"bcryptjs": "^3.0.3",
|
"bcryptjs": "^3.0.3",
|
||||||
|
"draco3dgltf": "^1.5.7",
|
||||||
"framer-motion": "^12.38.0",
|
"framer-motion": "^12.38.0",
|
||||||
"gsap": "^3.14.2",
|
"gsap": "^3.14.2",
|
||||||
"i18next": "^26.0.3",
|
"i18next": "^26.0.3",
|
||||||
@ -37,6 +41,7 @@
|
|||||||
"zustand": "^5.0.12"
|
"zustand": "^5.0.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@gltf-transform/cli": "^4.3.0",
|
||||||
"@tailwindcss/postcss": "^4.2.2",
|
"@tailwindcss/postcss": "^4.2.2",
|
||||||
"@testing-library/jest-dom": "^6.9.1",
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
"@testing-library/react": "^16.3.2",
|
"@testing-library/react": "^16.3.2",
|
||||||
|
|||||||
Binary file not shown.
BIN
public/Kandoura_original.glb
Normal file
BIN
public/Kandoura_original.glb
Normal file
Binary file not shown.
BIN
public/Suit.glb
BIN
public/Suit.glb
Binary file not shown.
BIN
public/Suit_original.glb
Normal file
BIN
public/Suit_original.glb
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/Unitree_G1_original.glb
Normal file
BIN
public/Unitree_G1_original.glb
Normal file
Binary file not shown.
BIN
public/Vest.glb
BIN
public/Vest.glb
Binary file not shown.
BIN
public/Vest_original.glb
Normal file
BIN
public/Vest_original.glb
Normal file
Binary file not shown.
@ -1,8 +1,22 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { cookies } from 'next/headers';
|
import { cookies } from 'next/headers';
|
||||||
import { jwtVerify } from 'jose';
|
import { jwtVerify } from 'jose';
|
||||||
import { writeFile, mkdir } from 'fs/promises';
|
import { writeFile, mkdir, readFile } from 'fs/promises';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { Document, NodeIO } from '@gltf-transform/core';
|
||||||
|
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
|
||||||
|
import { draco, dedup, prune, weld, simplify } from '@gltf-transform/functions';
|
||||||
|
import draco3d from 'draco3dgltf';
|
||||||
|
|
||||||
|
async function compressGLB(inputPath: string): Promise<void> {
|
||||||
|
const io = new NodeIO()
|
||||||
|
.registerExtensions(ALL_EXTENSIONS)
|
||||||
|
.registerDependencies({ 'draco3d.decoder': await draco3d.createDecoderModule(), 'draco3d.encoder': await draco3d.createEncoderModule() });
|
||||||
|
|
||||||
|
const document = await io.read(inputPath);
|
||||||
|
await document.transform(dedup(), prune(), weld(), draco());
|
||||||
|
await io.write(inputPath, document);
|
||||||
|
}
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
// Verify admin JWT
|
// Verify admin JWT
|
||||||
@ -51,6 +65,13 @@ export async function POST(request: Request) {
|
|||||||
const buffer = Buffer.from(await file.arrayBuffer());
|
const buffer = Buffer.from(await file.arrayBuffer());
|
||||||
await writeFile(destPath, buffer);
|
await writeFile(destPath, buffer);
|
||||||
|
|
||||||
|
// Compress the uploaded GLB with Draco to reduce file size
|
||||||
|
try {
|
||||||
|
await compressGLB(destPath);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('GLB compression failed, serving uncompressed:', err);
|
||||||
|
}
|
||||||
|
|
||||||
// Append a version timestamp so useGLTF cache is busted on replacement uploads
|
// Append a version timestamp so useGLTF cache is busted on replacement uploads
|
||||||
const version = Date.now();
|
const version = Date.now();
|
||||||
return NextResponse.json({ modelPath: `/models/${safeId}.glb?v=${version}` });
|
return NextResponse.json({ modelPath: `/models/${safeId}.glb?v=${version}` });
|
||||||
|
|||||||
@ -74,9 +74,9 @@ function OverlaySection({
|
|||||||
const panelStyle: React.CSSProperties = isCenter
|
const panelStyle: React.CSSProperties = isCenter
|
||||||
? { textAlign: 'center' }
|
? { textAlign: 'center' }
|
||||||
: {
|
: {
|
||||||
background: 'rgba(255, 255, 255, 0.45)',
|
background: 'rgba(255, 255, 255, 0.92)',
|
||||||
backdropFilter: 'blur(16px)',
|
backdropFilter: 'blur(20px)',
|
||||||
WebkitBackdropFilter: 'blur(16px)',
|
WebkitBackdropFilter: 'blur(20px)',
|
||||||
padding: '2.5rem',
|
padding: '2.5rem',
|
||||||
borderRadius: '1.5rem',
|
borderRadius: '1.5rem',
|
||||||
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.08)',
|
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.08)',
|
||||||
|
|||||||
@ -13,8 +13,8 @@ const CAMERA_KEYFRAMES: [number, [number, number, number]][] = [
|
|||||||
[0.40, [0.3, 1.5, 2.0]], // HEAD+CHEST: tight, high angle looking down
|
[0.40, [0.3, 1.5, 2.0]], // HEAD+CHEST: tight, high angle looking down
|
||||||
[0.55, [1.2, 2.2, 2.2]], // ABOVE: bird's eye with slight right offset
|
[0.55, [1.2, 2.2, 2.2]], // ABOVE: bird's eye with slight right offset
|
||||||
[0.68, [1.6, 0.7, 2.5]], // Dramatic right side sweep
|
[0.68, [1.6, 0.7, 2.5]], // Dramatic right side sweep
|
||||||
[0.80, [0.3, 0.3, 2.2]], // Circle to front-low
|
[0.80, [-1.8, 0.3, 3.0]], // Circle to front-left, pulled back to avoid text overlap
|
||||||
[0.92, [0, -0.3, 2.5]], // LOW ANGLE: heroic looking up
|
[0.92, [-1.5, -0.1, 3.2]], // LOW ANGLE: heroic, offset left for right-side text
|
||||||
[1.0, [0, 1.2, 5.5]], // Final: pull back for configurator
|
[1.0, [0, 1.2, 5.5]], // Final: pull back for configurator
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user