SparkSplat-Viewer / app /src /utils /worldLoader.ts
Jeprary
fix: allow blob: urls in worldLoader to enable local file dropping
ba04000
Raw
History Blame Contribute Delete
3.13 kB
import worlds from 'virtual:worlds'
import { type World, type WorldEntry } from '../types/world'
export function getExternalWorld(): WorldEntry | undefined {
if (typeof window === 'undefined') return undefined
const params = new URLSearchParams(window.location.search)
const modelUrl = params.get('model')
if (!modelUrl) return undefined
let finalUrl = modelUrl
let displayName = 'External Model'
if (modelUrl.startsWith('JYSM/')) {
const hfId = modelUrl.slice(5)
finalUrl = `https://huggingface.co/datasets/Junyueeeeee/SparkSplat_Model/resolve/main/${hfId}`
if (!finalUrl.toLowerCase().endsWith('.ply') && !finalUrl.toLowerCase().endsWith('.spz')) {
finalUrl += '.ply'
}
displayName = hfId
} else {
try {
const url = new URL(modelUrl)
const parts = url.pathname.split('/')
const filename = parts[parts.length - 1]
if (filename) displayName = decodeURIComponent(filename)
} catch (e) {}
}
const isSpz = finalUrl.toLowerCase().endsWith('.spz')
const world: World = {
world_id: 'external-model',
display_name: displayName,
assets: {
splats: {
ply_url: isSpz ? undefined : `${finalUrl}${finalUrl.includes('?') ? '&' : '?'}nocache=${Date.now()}`,
spz_urls: isSpz ? { full_res: `${finalUrl}${finalUrl.includes('?') ? '&' : '?'}nocache=${Date.now()}` } : {},
semantics_metadata: { metric_scale_factor: 1, ground_plane_offset: 0, flip_y: true }
},
mesh: { collider_mesh_url: '' },
imagery: { pano_url: '' },
thumbnail_url: '',
caption: ''
},
world_marble_url: '',
tags: [],
world_prompt: '',
created_at: '',
updated_at: ''
}
const dynamicSlug = `external-${displayName.replace(/[^a-zA-Z0-9_-]/g, '')}`
return {
slug: dynamicSlug,
project: { slug: dynamicSlug, display_name: displayName },
world,
worldVersions: [{ index: 1, label: 'v1', complete: true, world }],
objectAssets: [],
allObjectAssets: [],
sourceImageVersions: [],
worldSfxUrls: []
}
}
export function loadWorlds(): WorldEntry[] {
const external = getExternalWorld()
const local = worlds as WorldEntry[]
return external ? [external, ...local] : local
}
export async function fetchWorlds(): Promise<WorldEntry[]> {
const external = getExternalWorld()
if (!import.meta.env.DEV) {
const local = worlds as WorldEntry[]
return external ? [external, ...local] : local
}
const response = await fetch('/__models', { cache: 'no-store' })
if (!response.ok) throw new Error(await response.text())
const fetched = await response.json() as WorldEntry[]
return external ? [external, ...fetched] : fetched
}
function localWorldAssetUrl(url: string | undefined): string {
if (!url) return ''
return url.startsWith('http') || url.startsWith('/models/') || url.startsWith('blob:') ? url : ''
}
export function getSplatUrl(world: World): string {
if (world.assets.splats.ply_url) {
return localWorldAssetUrl(world.assets.splats.ply_url)
}
const urls = world.assets.splats.spz_urls
return localWorldAssetUrl(urls.full_res)
}