316 lines
8.4 KiB
TypeScript
316 lines
8.4 KiB
TypeScript
import type { AssetInput } from '@pascal-app/core/schema'
|
|
|
|
/**
|
|
* Small built-in catalog for standalone/headless MCP use.
|
|
*
|
|
* The editor has a much larger UI catalog, but depending on `@pascal-app/editor`
|
|
* from the MCP package would pull browser/React code into the headless server.
|
|
* These entries mirror the stable IDs and asset paths used by the editor for
|
|
* common AI-generated residential layouts.
|
|
*/
|
|
export const MCP_CATALOG_ITEMS: AssetInput[] = [
|
|
{
|
|
id: 'double-bed',
|
|
category: 'furniture',
|
|
tags: ['floor', 'bedroom'],
|
|
name: 'Double Bed',
|
|
thumbnail: '/items/double-bed/thumbnail.webp',
|
|
src: '/items/double-bed/model.glb',
|
|
dimensions: [2, 0.8, 2.5],
|
|
offset: [0, 0, -0.03],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'single-bed',
|
|
category: 'furniture',
|
|
tags: ['floor', 'bedroom'],
|
|
name: 'Single Bed',
|
|
thumbnail: '/items/single-bed/thumbnail.webp',
|
|
src: '/items/single-bed/model.glb',
|
|
dimensions: [1.5, 0.7, 2.5],
|
|
offset: [0, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'bedside-table',
|
|
category: 'furniture',
|
|
tags: ['floor', 'bedroom'],
|
|
name: 'Bedside Table',
|
|
thumbnail: '/items/bedside-table/thumbnail.webp',
|
|
src: '/items/bedside-table/model.glb',
|
|
dimensions: [0.5, 0.5, 0.5],
|
|
offset: [0, 0, -0.01],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
surface: { height: 0.5 },
|
|
},
|
|
{
|
|
id: 'dresser',
|
|
category: 'furniture',
|
|
tags: ['floor', 'storage', 'bedroom'],
|
|
name: 'Dresser',
|
|
thumbnail: '/items/dresser/thumbnail.webp',
|
|
src: '/items/dresser/model.glb',
|
|
dimensions: [1.5, 0.8, 1],
|
|
offset: [0, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
surface: { height: 0.8 },
|
|
},
|
|
{
|
|
id: 'closet',
|
|
category: 'furniture',
|
|
tags: ['floor', 'storage', 'bedroom'],
|
|
name: 'Closet',
|
|
thumbnail: '/items/closet/thumbnail.webp',
|
|
src: '/items/closet/model.glb',
|
|
dimensions: [2, 2.5, 1],
|
|
offset: [0, 0, -0.01],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'sofa',
|
|
category: 'furniture',
|
|
tags: ['floor', 'seating', 'living'],
|
|
name: 'Sofa',
|
|
thumbnail: '/items/sofa/thumbnail.webp',
|
|
src: '/items/sofa/model.glb',
|
|
dimensions: [2.5, 0.8, 1.5],
|
|
offset: [0, 0, 0.04],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'livingroom-chair',
|
|
category: 'furniture',
|
|
tags: ['floor', 'seating', 'living'],
|
|
name: 'Livingroom Chair',
|
|
thumbnail: '/items/livingroom-chair/thumbnail.webp',
|
|
src: '/items/livingroom-chair/model.glb',
|
|
dimensions: [1.5, 0.8, 1.5],
|
|
offset: [0.01, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'coffee-table',
|
|
category: 'furniture',
|
|
tags: ['floor', 'table', 'living'],
|
|
name: 'Coffee Table',
|
|
thumbnail: '/items/coffee-table/thumbnail.webp',
|
|
src: '/items/coffee-table/model.glb',
|
|
dimensions: [2, 0.4, 1.5],
|
|
offset: [0, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
surface: { height: 0.3 },
|
|
},
|
|
{
|
|
id: 'tv-stand',
|
|
category: 'furniture',
|
|
tags: ['floor', 'storage', 'living'],
|
|
name: 'TV Stand',
|
|
thumbnail: '/items/tv-stand/thumbnail.webp',
|
|
src: '/items/tv-stand/model.glb',
|
|
dimensions: [2, 0.4, 0.5],
|
|
offset: [0, 0.21, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
surface: { height: 0.36 },
|
|
},
|
|
{
|
|
id: 'shelf',
|
|
category: 'furniture',
|
|
tags: ['wall', 'storage'],
|
|
name: 'Shelf',
|
|
thumbnail: '/items/shelf/thumbnail.webp',
|
|
src: '/items/shelf/model.glb',
|
|
dimensions: [1, 0.5, 0.7],
|
|
offset: [0, 0.1, 0.01],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
attachTo: 'wall-side',
|
|
surface: { height: 0.12 },
|
|
},
|
|
{
|
|
id: 'dining-table',
|
|
category: 'furniture',
|
|
tags: ['floor', 'table', 'dining'],
|
|
name: 'Dining Table',
|
|
thumbnail: '/items/dining-table/thumbnail.webp',
|
|
src: '/items/dining-table/model.glb',
|
|
dimensions: [2.5, 0.8, 1],
|
|
offset: [0, 0, -0.01],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
surface: { height: 0.8 },
|
|
},
|
|
{
|
|
id: 'dining-chair',
|
|
category: 'furniture',
|
|
tags: ['floor', 'seating', 'dining'],
|
|
name: 'Dining Chair',
|
|
thumbnail: '/items/dining-chair/thumbnail.webp',
|
|
src: '/items/dining-chair/model.glb',
|
|
dimensions: [0.5, 1, 0.5],
|
|
offset: [0, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'kitchen',
|
|
category: 'kitchen',
|
|
tags: ['floor', 'large', 'kitchen'],
|
|
name: 'Kitchen',
|
|
thumbnail: '/items/kitchen/thumbnail.webp',
|
|
src: '/items/kitchen/model.glb',
|
|
dimensions: [2.5, 1.1, 1],
|
|
offset: [0, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'kitchen-counter',
|
|
category: 'kitchen',
|
|
tags: ['floor', 'large', 'storage', 'kitchen'],
|
|
name: 'Kitchen Counter',
|
|
thumbnail: '/items/kitchen-counter/thumbnail.webp',
|
|
src: '/items/kitchen-counter/model.glb',
|
|
dimensions: [2, 0.8, 1],
|
|
offset: [0, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
surface: { height: 0.75 },
|
|
},
|
|
{
|
|
id: 'stove',
|
|
category: 'kitchen',
|
|
tags: ['floor', 'large', 'kitchen'],
|
|
name: 'Stove',
|
|
thumbnail: '/items/stove/thumbnail.webp',
|
|
src: '/items/stove/model.glb',
|
|
dimensions: [1, 1, 1],
|
|
offset: [0, 0, -0.05],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'fridge',
|
|
category: 'kitchen',
|
|
tags: ['floor', 'large', 'kitchen'],
|
|
name: 'Fridge',
|
|
thumbnail: '/items/fridge/thumbnail.webp',
|
|
src: '/items/fridge/model.glb',
|
|
dimensions: [1, 2, 1],
|
|
offset: [0.01, 0, -0.05],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'toilet',
|
|
category: 'bathroom',
|
|
tags: ['floor', 'large', 'bathroom'],
|
|
name: 'Toilet',
|
|
thumbnail: '/items/toilet/thumbnail.webp',
|
|
src: '/items/toilet/model.glb',
|
|
dimensions: [1, 0.9, 1],
|
|
offset: [0, 0, -0.23],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'bathroom-sink',
|
|
category: 'bathroom',
|
|
tags: ['floor', 'large', 'bathroom'],
|
|
name: 'Bathroom Sink',
|
|
thumbnail: '/items/bathroom-sink/thumbnail.webp',
|
|
src: '/items/bathroom-sink/model.glb',
|
|
dimensions: [2, 1, 1.5],
|
|
offset: [0.11, 0, 0.02],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'shower-square',
|
|
category: 'bathroom',
|
|
tags: ['floor', 'large', 'bathroom'],
|
|
name: 'Squared Shower',
|
|
thumbnail: '/items/shower-square/thumbnail.webp',
|
|
src: '/items/shower-square/model.glb',
|
|
dimensions: [1, 2, 1],
|
|
offset: [0.41, 0, -0.42],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'bathtub',
|
|
category: 'bathroom',
|
|
tags: ['floor', 'large', 'bathroom'],
|
|
name: 'Bathtub',
|
|
thumbnail: '/items/bathtub/thumbnail.webp',
|
|
src: '/items/bathtub/model.glb',
|
|
dimensions: [2.5, 0.8, 1.5],
|
|
offset: [0, 0, 0.01],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'washing-machine',
|
|
category: 'bathroom',
|
|
tags: ['floor', 'large', 'electronics', 'laundry'],
|
|
name: 'Washing Machine',
|
|
thumbnail: '/items/washing-machine/thumbnail.webp',
|
|
src: '/items/washing-machine/model.glb',
|
|
dimensions: [1, 1, 1],
|
|
offset: [0, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'drying-rack',
|
|
category: 'bathroom',
|
|
tags: ['floor', 'laundry'],
|
|
name: 'Drying Rack',
|
|
thumbnail: '/items/drying-rack/thumbnail.webp',
|
|
src: '/items/drying-rack/model.glb',
|
|
dimensions: [2, 1.1, 1],
|
|
offset: [0, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
{
|
|
id: 'coat-rack',
|
|
category: 'furniture',
|
|
tags: ['floor', 'storage', 'entry'],
|
|
name: 'Coat Rack',
|
|
thumbnail: '/items/coat-rack/thumbnail.webp',
|
|
src: '/items/coat-rack/model.glb',
|
|
dimensions: [0.5, 1.8, 0.5],
|
|
offset: [0, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
scale: [1, 1, 1],
|
|
},
|
|
]
|
|
|
|
export function findCatalogItem(id: string): AssetInput | undefined {
|
|
return MCP_CATALOG_ITEMS.find((item) => item.id === id)
|
|
}
|
|
|
|
export function searchCatalogItems(args: {
|
|
query: string
|
|
category?: string | undefined
|
|
}): AssetInput[] {
|
|
const terms = args.query.trim().toLowerCase().split(/\s+/).filter(Boolean)
|
|
|
|
return MCP_CATALOG_ITEMS.filter((item) => {
|
|
if (args.category && item.category !== args.category) return false
|
|
const haystack = [item.id, item.name, item.category, ...(item.tags ?? [])]
|
|
.join(' ')
|
|
.toLowerCase()
|
|
return terms.every((term) => haystack.includes(term))
|
|
})
|
|
}
|