From 5cfe9e90680458f76d8774c63b7bd3e72e674efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Goszczy=C5=84ski?= Date: Tue, 11 Mar 2025 12:30:54 +0100 Subject: [PATCH] stash changes --- apps/www/components/LaunchWeek/14/canvas.tsx | 4 +- apps/www/components/LaunchWeek/14/helpers.ts | 109 +- .../images/launchweek/14/bilet-supabase.glb | Bin 9264 -> 0 bytes .../images/launchweek/14/bilet-supabase.gltf | 419 ----- .../14/ticket-supabase-positioned.gltf | 1420 +++++++++++++++++ 5 files changed, 1492 insertions(+), 460 deletions(-) delete mode 100644 apps/www/public/images/launchweek/14/bilet-supabase.glb delete mode 100644 apps/www/public/images/launchweek/14/bilet-supabase.gltf create mode 100644 apps/www/public/images/launchweek/14/ticket-supabase-positioned.gltf diff --git a/apps/www/components/LaunchWeek/14/canvas.tsx b/apps/www/components/LaunchWeek/14/canvas.tsx index d8848ca4f9d..083c712c864 100644 --- a/apps/www/components/LaunchWeek/14/canvas.tsx +++ b/apps/www/components/LaunchWeek/14/canvas.tsx @@ -68,9 +68,9 @@ const LwCanvas = ({ className }: { className?: string }) => { // Load the ticket texture and create the actual ticket mesh // Replace this URL with your actual ticket texture - const ticketTextureUrl = '/images/launchweek/14/ticket-test.png' + const ticketScene = '/images/launchweek/14/ticket-supabase-positioned.gltf' - createTicketMesh(ticketTextureUrl, { + createTicketMesh(ticketScene, { width: planeGeometrySize[0], height: planeGeometrySize[1], }) diff --git a/apps/www/components/LaunchWeek/14/helpers.ts b/apps/www/components/LaunchWeek/14/helpers.ts index f02fc0f96b6..fc233eb120d 100644 --- a/apps/www/components/LaunchWeek/14/helpers.ts +++ b/apps/www/components/LaunchWeek/14/helpers.ts @@ -7,13 +7,15 @@ import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js' import { GlitchPass } from './glitch' import { CRTShader } from './crt-shader' +import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js' +import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js' /** - * Custom hook for managing requestAnimationFrame + * Helper to simplifies controlling requestAnimationFrame * @param callback Animation callback function * @returns Object with start and stop functions */ -export const useThreeAnimation = (callback: (time?: number) => void) => { +export const createThreeAnimation = (callback: (time?: number) => void) => { const requestRef = { current: undefined } as { current: number | undefined } const previousTimeRef = { current: undefined } as { current: number | undefined } @@ -47,7 +49,7 @@ export const useThreeAnimation = (callback: (time?: number) => void) => { export const createThreeSetup = ( container: HTMLElement, options: { - cameraPosition?: THREE.Vector3, + cameraPosition?: THREE.Vector3 postprocessing?: { bloom?: { enabled: boolean @@ -200,88 +202,114 @@ export const createTicketMesh = async ( try { const width = options.width || 4 const height = options.height || 2 - + // Determine if we should use texture mode - const useTextureMode = options.forceTextureMode || - !(source.endsWith('.glb') || source.endsWith('.gltf')) - + const useTextureMode = + options.forceTextureMode || !(source.endsWith('.glb') || source.endsWith('.gltf')) + if (!useTextureMode) { // Load the GLTF model const model = await loadGLTFModel(source) - + + const namedObject = model.getObjectByName('planetName') + + const boxHelper = new THREE.BoxHelper(namedObject, 0xff0000) // Red outline + model.add(boxHelper) // Add to the model so it moves with it + + const fontLoader = new FontLoader() + + fontLoader.load('/images/launchweek/13/ticket/SourceCodePro_Regular.json', function (font) { + const textGeometry = new TextGeometry('Earth', { + font: font, + size: 96, + depth: 0.05, + }) + + const textMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff }) + const textMesh = new THREE.Mesh(textGeometry, textMaterial) + + // Add text as child of your named object + if (namedObject) namedObject.add(textMesh) + else console.error('Named object not found') + + // Position relative to parent + textMesh.position.set(0, 0, 0.01) // Slight offset to avoid z-fighting + }) + // Calculate scale to fit the model within the specified width and height const box = new THREE.Box3().setFromObject(model) const size = box.getSize(new THREE.Vector3()) - + // Calculate scale factors to fit the model within the specified dimensions const scaleX = width / size.x const scaleY = height / size.y const scale = Math.min(scaleX, scaleY) - + // Apply the scale model.scale.set(scale, scale, scale) - + // Center the model box.setFromObject(model) const center = box.getCenter(new THREE.Vector3()) model.position.sub(center) - + // Only enhance emissive properties if explicitly requested // This respects the original GLTF materials by default if (options.enhanceEmissive) { model.traverse((child) => { if (child instanceof THREE.Mesh && child.material) { if (Array.isArray(child.material)) { - child.material.forEach(mat => { + child.material.forEach((mat) => { if (mat instanceof THREE.MeshStandardMaterial) { - mat.emissive = options.materialOptions?.emissiveColor - ? new THREE.Color(options.materialOptions.emissiveColor) + mat.emissive = options.materialOptions?.emissiveColor + ? new THREE.Color(options.materialOptions.emissiveColor) : new THREE.Color(0xffffff) mat.emissiveIntensity = options.materialOptions?.emissiveIntensity ?? 0.2 } }) } else if (child.material instanceof THREE.MeshStandardMaterial) { - child.material.emissive = options.materialOptions?.emissiveColor - ? new THREE.Color(options.materialOptions.emissiveColor) + child.material.emissive = options.materialOptions?.emissiveColor + ? new THREE.Color(options.materialOptions.emissiveColor) : new THREE.Color(0xffffff) child.material.emissiveIntensity = options.materialOptions?.emissiveIntensity ?? 0.2 } } }) } - + return model } else { // Load as a texture const texture = await loadTexture(source) - + // Create a plane geometry for the ticket const geometry = new THREE.PlaneGeometry(width, height) - + // Create a material with the loaded texture const material = new THREE.MeshStandardMaterial({ map: texture, - transparent: options.materialOptions?.transparent !== undefined - ? options.materialOptions.transparent - : true, + transparent: + options.materialOptions?.transparent !== undefined + ? options.materialOptions.transparent + : true, side: THREE.DoubleSide, - emissive: options.materialOptions?.emissiveColor - ? new THREE.Color(options.materialOptions.emissiveColor) + emissive: options.materialOptions?.emissiveColor + ? new THREE.Color(options.materialOptions.emissiveColor) : new THREE.Color(0xffffff), emissiveIntensity: options.materialOptions?.emissiveIntensity ?? 0.2, - color: options.materialOptions?.color - ? new THREE.Color(options.materialOptions.color) + color: options.materialOptions?.color + ? new THREE.Color(options.materialOptions.color) : new THREE.Color(0xffffff), }) - + // Create the mesh const mesh = new THREE.Mesh(geometry, material) - + return mesh } } catch (error) { console.error('Error loading model/texture:', error) - + // Fallback to a simple plane with a default material if loading fails const geometry = new THREE.PlaneGeometry(options.width || 4, options.height || 2) const material = new THREE.MeshStandardMaterial({ @@ -291,7 +319,7 @@ export const createTicketMesh = async ( emissive: new THREE.Color(0xffffff), emissiveIntensity: 0.2, }) - + return new THREE.Mesh(geometry, material) } } @@ -317,7 +345,7 @@ export const createTextureTicketMesh = async ( ): Promise => { return createTicketMesh(textureUrl, { ...options, - forceTextureMode: true + forceTextureMode: true, }) as Promise } @@ -327,26 +355,29 @@ export const createTextureTicketMesh = async ( * @returns Object with containerRef */ export const useThreeJS = ( - setupCallback: (container: HTMLElement) => { cleanup: () => void; animate: (time?: number) => void } + setupCallback: (container: HTMLElement) => { + cleanup: () => void + animate: (time?: number) => void + } ) => { const containerRef = useRef(null) - + useEffect(() => { if (!containerRef.current) return - + const container = containerRef.current const { cleanup, animate } = setupCallback(container) - + // Set up animation loop - const { start, stop } = useThreeAnimation(animate) + const { start, stop } = createThreeAnimation(animate) start() - + // Cleanup on unmount return () => { stop() cleanup() } }, [setupCallback]) - + return { containerRef } } diff --git a/apps/www/public/images/launchweek/14/bilet-supabase.glb b/apps/www/public/images/launchweek/14/bilet-supabase.glb deleted file mode 100644 index bf8115cc2c0e0d47ea2c517a1b84abe56cedfb98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9264 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