
Cottage with swappable parts
A second house shell on a 4 m lot with a hip roof by default.
What you can change
- Size (W × H × D)
- 3.84 × 6.02 × 6.66 m
- Triangles
- 14,608
- GLB
- 875 KB
Part of the Stylized Town kit
npx agent-ready-assets add stylized-town/house-02@0.1.0 --to public/assetsRenders from 6 views






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.
Front doorPart swap
Window stylePart swap
RoofPart swap
Wall colorRecolour
Roof colorRecolour
Details
Specifications14,608 triangles · 875 KB
- Dimensions (W × H × D)
- 3.84 × 6.02 × 6.66 m
- Triangles
- 14,608
- Materials / textures
- 7 / 0
- GLB file
- 875 KB
- Package download
- 257 KB
- Animation clips
- None
- Engines
- Three.js, React Three Fiber
- Tested with
- three 0.186.1; no decoders
- In the tested scenes
- Explorable town (3×)
- Parts it mounts
- Door part: panelled door, Door part: glazed door, Roof part: gable roof, Roof part: hip roof, Window part: framed window, Window part: shuttered window
Connectors10 connectors
In a scene, a connector of this asset snaps to a compatible connector of another piece, so pieces are placed without coordinates.
| Connector | Type | Snaps to |
|---|---|---|
anchor-lot-front | lot-front | road-side |
anchor-door-main (part slot) | door-socket | door-plug |
anchor-window-front-0-1 (part slot) | window-socket | window-plug |
anchor-window-back-0-1 (part slot) | window-socket | window-plug |
anchor-window-back-0-2 (part slot) | window-socket | window-plug |
anchor-window-left-0-1 (part slot) | window-socket | window-plug |
anchor-window-left-0-2 (part slot) | window-socket | window-plug |
anchor-window-right-0-1 (part slot) | window-socket | window-plug |
anchor-window-right-0-2 (part slot) | window-socket | window-plug |
anchor-roof (part slot) | roof-socket-house | roof-plug-house |
Compatibility4 of 10 supported
| Feature | Status | Detail |
|---|---|---|
| Material recolor (runtime, Blender-free) | Supported | wall-color -> mat-wall (palette swatches: ivory #EDE3CF, paving #E3C2AC, leaf #7FA36B); roof-color -> mat-roof (palette swatches: terracotta #C97755, terracotta-dark #A65F43, curb-stone #A9A398)… Show allwall-color -> mat-wall (palette swatches: ivory #EDE3CF, paving #E3C2AC, leaf #7FA36B); roof-color -> mat-roof (palette swatches: terracotta #C97755, terracotta-dark #A65F43, 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) | Supported | scene.json position_m (meters) and rotation_euler_rad (XYZ radians); free scene scaling is not supported |
| Connector snapping (scene 1.1.0 attach_to) | Supported | typed connectors: anchor-lot-front (lot-front -> road-side), anchor-door-main (door-socket -> door-plug), anchor-window-front-0-1 (window-socket -> window-plug), anchor-window-back-0-1 (window-socket… Show alltyped connectors: anchor-lot-front (lot-front -> road-side), anchor-door-main (door-socket -> door-plug), anchor-window-front-0-1 (window-socket -> window-plug), anchor-window-back-0-1 (window-socket -> window-plug), anchor-window-back-0-2 (window-socket -> window-plug), anchor-window-left-0-1 (window-socket -> window-plug), anchor-window-left-0-2 (window-socket -> window-plug), anchor-window-right-0-1 (window-socket -> window-plug), anchor-window-right-0-2 (window-socket -> window-plug), anchor-roof (roof-socket-house -> roof-plug-house); mates within 1 mm, opposed outward, aligned up |
| Modular part swap | Supported | 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; window-style at anchor-window-front-0-1, anchor-window-back-0-1… 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; window-style at anchor-window-front-0-1, anchor-window-back-0-1, anchor-window-back-0-2, anchor-window-left-0-1, anchor-window-left-0-2, anchor-window-right-0-1, anchor-window-right-0-2: window-01 -> stylized-town/window-01@0.1.0, window-02 (default) -> stylized-town/window-02@0.1.0; roof at anchor-roof: roof-gable-01 -> stylized-town/roof-gable-01@0.1.0, roof-hip-01 (default) -> stylized-town/roof-hip-01@0.1.0 (allowlisted parts of the same kit with a compatible plug; mounted per instance) |
| Uniform scale (runtime, Blender-free) | Not supported | no uniform-scale capability; scene uniform_scale must stay 1 |
| Node visibility toggles | Not supported | no node-visibility capability is advertised for this version |
| Animations | Not supported | static asset: no animation clips |
| Custom mesh editing / parametric geometry (e.g. slat count) | Advanced only | L4 authoring in Blender or another DCC; not possible with the SDK. declared.recipe_parameters are publisher-only knobs. |
| Baked texture recolor | Not supported | texture pixels are never edited by the SDK |
| GLB re-export of a customized asset | Not supported | customization 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
// stylized-town/house-02@0.1.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/house-02@0.1.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, window-style, roof, wall-color, roof-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","window-style":"window-01","roof":"roof-gable-01","wall-color":"paving","roof-color":"terracotta-dark"});
customized.object.position.x = 4.84;
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
// stylized-town/house-02@0.1.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/house-02@0.1.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: [8.66, 5.99, 12.65], 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.42, 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","window-style":"window-01","roof":"roof-gable-01","wall-color":"paving","roof-color":"terracotta-dark"}} position={[2.42, 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),
);
{
"schema_version": "1.0.0",
"asset": "stylized-town/house-02@0.1.0",
"values": {
"front-door": "door-01",
"window-style": "window-01",
"roof": "roof-gable-01",
"wall-color": "paving",
"roof-color": "terracotta-dark"
}
}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