Render of Corner shop with swappable parts
The 3D view loads a preview copy of this asset with the SDK.
Buildings

Corner shop with swappable parts

Shop on a 4 m lot with a shop window front.

What you can change

Front door · 2 choices Awning · show or hide Wall color · 3 swatches
Size (W × H × D)
3.85 × 4.56 × 5.46 m
Triangles
3,264
GLB
214 KB

Part of the Stylized Town kit

Install with the CLI
npx agent-ready-assets add stylized-town/shop-01@0.2.0 --to public/assets

Renders from 6 views

Corner shop with swappable parts, front view
front
Corner shop with swappable parts, back view
back
Corner shop with swappable parts, left view
left
Corner shop with swappable parts, right view
right
Corner shop with swappable parts, top view
top
Corner shop with swappable parts, perspective view
perspective

Customize without Blender

Each change applies to one instance in the browser through the SDK; other instances and the file itself stay unchanged. Anything not listed here is refused with an explanation.

AwningVisibility toggle

Shown by default; can be hidden

Wall colorRecolour

ivory (default) paving curb-stone

Details

Specifications3,264 triangles · 214 KB
Dimensions (W × H × D)
3.85 × 4.56 × 5.46 m
Triangles
3,264
Materials / textures
7 / 1
GLB file
214 KB
Package download
108 KB
Animation clips
None
Engines
Three.js, React Three Fiber
Tested with
three 0.186.1; no decoders
In the tested scenes
Small town (1×), Explorable town (3×)
Parts it mounts
Door part: panelled door, Door part: glazed door
Connectors3 connectors

In a scene, a connector of this asset snaps to a compatible connector of another piece, so pieces are placed without coordinates.

ConnectorTypeSnaps to
anchor-lot-frontlot-frontroad-side
anchor-door-main (part slot)door-socketdoor-plug
anchor-awningawning-socketawning-plug
Compatibility5 of 10 supported
FeatureStatusDetail
Material recolor (runtime, Blender-free)Supportedwall-color -> mat-wall (palette swatches: ivory #EDE3CF, paving #E3C2AC, curb-stone #A9A398) (per-instance, host and mounted parts; base color factor of untextured materials, not baked texture pixels)
Placement (position / rotation in a scene)Supportedscene.json position_m (meters) and rotation_euler_rad (XYZ radians); free scene scaling is not supported
Connector snapping (scene 1.1.0 attach_to)Supportedtyped connectors: anchor-lot-front (lot-front -> road-side), anchor-door-main (door-socket -> door-plug), anchor-awning (awning-socket -> awning-plug); mates within 1 mm, opposed outward, aligned up
Node visibility togglesSupportedawning: false hides awning (declared optional parts only; anchors, markers and slot parts never disappear)
Modular part swapSupported
front-door at anchor-door-main: door-01 -> stylized-town/door-01@0.1.0, door-02 (default) -> stylized-town/door-02@0.1.0 (allowlisted parts of the same kit with a compatible plug; mounted per… Show allfront-door at anchor-door-main: door-01 -> stylized-town/door-01@0.1.0, door-02 (default) -> stylized-town/door-02@0.1.0 (allowlisted parts of the same kit with a compatible plug; mounted per instance)
Uniform scale (runtime, Blender-free)Not supportedno uniform-scale capability; scene uniform_scale must stay 1
AnimationsNot supportedstatic asset: no animation clips
Custom mesh editing / parametric geometry (e.g. slat count)Advanced onlyL4 authoring in Blender or another DCC; not possible with the SDK. declared.recipe_parameters are publisher-only knobs.
Baked texture recolorNot supportedtexture pixels are never edited by the SDK
GLB re-export of a customized assetNot supportedcustomization is a declarative JSON config applied at runtime; no modified GLB is written
Integration codeThree.js and React Three Fiber

The entry file your agent writes, generated from the catalog. Run the commands inside your project, where the SDK is installed.

Three.js

src/main.ts
// stylized-town/shop-01@0.2.0 in a plain Three.js scene
// Generated by the Agent-Ready Assets integration guide (target: plain Three.js, SDK 0.5.1, tested with three 0.186.1).
// The files are served from this project's own public/ folder (installed with `npx agent-ready-assets ...`):
// no CDN at runtime, no decoders, no Blender.
import * as THREE from 'three';
import { AssetLibrary, isCustomizationError } from '@agent-ready-assets/runtime-three';

const KIT_URL = '/assets/stylized-town/kit.json';
const ASSET = 'stylized-town/shop-01@0.2.0';

const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.outputColorSpace = THREE.SRGBColorSpace;
document.body.style.margin = '0';
document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();
scene.background = new THREE.Color('#e9e4da');
scene.add(new THREE.HemisphereLight(0xffffff, 0x8d7c64, 1.4));
const sun = new THREE.DirectionalLight(0xffffff, 2.0);
sun.position.set(4, 8, 5);
scene.add(sun);
const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.05, 400);

/** Points the camera at everything that was loaded (3/4 view). */
function frame(target: THREE.Object3D): void {
  const box = new THREE.Box3().setFromObject(target);
  const center = box.getCenter(new THREE.Vector3());
  const radius = Math.max(box.getSize(new THREE.Vector3()).length() / 2, 0.5);
  const dist = radius / Math.sin(THREE.MathUtils.degToRad(camera.fov / 2));
  camera.position.copy(center).add(new THREE.Vector3(0.55, 0.5, 1).normalize().multiplyScalar(dist * 0.95));
  camera.lookAt(center);
  camera.updateProjectionMatrix();
}

window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.render(scene, camera);
});

async function main(): Promise<void> {
  const library = await AssetLibrary.fromKit(KIT_URL); // verifies every file against the sha256 pins first
  const original = await library.loadAsset(ASSET);
  scene.add(original.object);
  // Only the capabilities returned by get_customization_capabilities exist (here: front-door, awning, wall-color).
  // Each customized instance gets its own material copies and mounted parts; the original and the cached GLB stay unchanged.
  const customized = await library.instantiate(ASSET, {"front-door":"door-01","awning":false,"wall-color":"paving"});
  customized.object.position.x = 4.85;
  scene.add(customized.object);
  frame(scene);
  renderer.render(scene, camera);
  renderer.domElement.dataset.ready = 'true'; // handy for tests: the scene finished loading
}

main().catch((error: unknown) => {
  // Unsupported or invalid customizations are refused with a structured error instead of being approximated.
  const message = isCustomizationError(error) ? `${error.code}: ${error.message}` : String(error);
  renderer.domElement.dataset.error = message;
  console.error(message);
});

React Three Fiber

src/main.tsx
// stylized-town/shop-01@0.2.0 with React Three Fiber
// Generated by the Agent-Ready Assets integration guide (target: React Three Fiber, SDK 0.5.1, tested with three 0.186.1).
// Assets are served from this project's own public/ folder; no CDN, no Blender.
import { StrictMode, useEffect, useState } from 'react';
import { createRoot } from 'react-dom/client';
import { Canvas } from '@react-three/fiber';
import { Asset, AssetLibraryProvider } from '@agent-ready-assets/runtime-r3f';
import { AssetLibrary } from '@agent-ready-assets/runtime-three';

const KIT_URL = '/assets/stylized-town/kit.json';
const ASSET = 'stylized-town/shop-01@0.2.0';

/** Marks the canvas once every <Asset> reported onReady (handy for tests). */
function useReadyFlag(expected: number): () => void {
  const [count, setCount] = useState(0);
  useEffect(() => {
    if (count >= expected) document.querySelector('canvas')?.setAttribute('data-ready', 'true');
  }, [count, expected]);
  return () => setCount((n) => n + 1);
}

function App({ library }: { library: AssetLibrary }) {
  const onReady = useReadyFlag(2);
  return (
    <Canvas camera={{ position: [7.09, 4.91, 10.36], fov: 40 }} gl={{ preserveDrawingBuffer: true }}>
      <color attach="background" args={['#e9e4da']} />
      <hemisphereLight args={[0xffffff, 0x8d7c64, 1.4]} />
      <directionalLight position={[4, 8, 5]} intensity={2} />
      <AssetLibraryProvider library={library}>
        <Asset assetId={ASSET} position={[-2.425, 0, 0]} onReady={onReady} onError={(e) => console.error(e)} />
        {/* customize accepts only declared capabilities; anything else calls onError with UNSUPPORTED_OPERATION */}
        <Asset assetId={ASSET} customize={{"front-door":"door-01","awning":false,"wall-color":"paving"}} position={[2.425, 0, 0]} onReady={onReady} onError={(e) => console.error(e)} />
      </AssetLibraryProvider>
    </Canvas>
  );
}

AssetLibrary.fromKit(KIT_URL).then(
  (library) => createRoot(document.getElementById('root')!).render(<StrictMode><App library={library} /></StrictMode>),
  (error: unknown) => console.error(error),
);
shop-01.customization.json
{
  "schema_version": "1.0.0",
  "asset": "stylized-town/shop-01@0.2.0",
  "values": {
    "front-door": "door-01",
    "awning": false,
    "wall-color": "paving"
  }
}
Quality reportAutomated checks passed

Every automated check that applies passed on this exact file, including glTF validity, scale and pivots, materials and a Three.js render in Chromium. The asset was released after review.

These are the publisher's own automated checks, not an independent certification.

Read the full report