Skip to content
Kiln0.10Get Kiln

Stepped walnut cabinet with a brass grille and tuning controls

Earlier examples from earlier Kiln versions.

Historical gallery render of Deco radio; see the poster provenance below.

Drag to orbit after opening. The model starts stationary.

For your engine. The download is a standard glTF 2.0 binary (GLB) with PBR metallic-roughness materials. glTF stores materials, not lighting or tone mapping, so your engine decides how they read. This 3D view tone-maps with Review Neutral, the Khronos PBR Neutral construction with a smaller glare offset (0.015 instead of 0.04), at exposure 0.9. Its Tone mapping control also shows ACES and Linear, for comparison.

Build measurements

Triangles
13,216
Estimated draws
158
Materials
11
Textures
0
Animation clips
1
Bounds X × Y × Z
0.21 × 0.39 × 0.34 m
Build warnings
0

Measurements come from this build.

Download this build

Runtime: 206,416 bytes. Original: 206,192 bytes.

These GLBs are build outputs of the MIT-licensed example source; no separate terms are stated for the builds.

Runtime provenance metadata
SHA-256 download hashes
Runtime GLB
9bc36f8616f1485e1099ebf80697ebdc08f3157a78f6175975a3e2ccba62a191
Original GLB
5ef16001317b96858e46b5c17a29128d7edb3b12346c55be7663758ab42e8cb7
Source
f0c0ec0dee84e5b8714744a16f8e66399ad66f35a415ad974c409efed4b7bf73

The example source is part of the Kiln repository. Repository licence: MIT.

These GLBs are build outputs of the MIT-licensed example source; no separate terms are stated for the builds.

Recorded authorship

Gemini 3.8 Flash through Antigravity CLI (agy) ·

Recorded Antigravity / gemini-3.8-flash-high run; configured model, no provider-internal attestation. Subsequent rear-panel repair by a Codex maintainer agent is recorded in source history.

Source access
Fresh project-local authoring workspace with a brief, installed skills and Kiln tools.
Inherited context
Fresh independent authoring conversation.
Starting example
None supplied.
Human input
Maintainer supplied the brief and reviewed exports. Codex maintainer agent subsequently resized the rear panels to fit within the cabinet faces, matched the walnut finish, and repositioned rear details. Original model source is retained in revision history.
Authoring review
Actual GPU images inspected independently. The author repaired grille and dial orientation after image review. Dial markings remain pale; this is a decorative asset, not a functioning radio. Subsequent maintainer repair inspected in actual front and rear GPU images; rear panels no longer protrude beyond the stepped cabinet.

Gallery GPU render of this exact source. The separate poster receipt records image, camera, renderer, and the artifact hash of the GLB bytes the image was rendered from.

Poster camera and render record

The source behind this build

deco-radio.kiln.js
// Art Deco Radio - Collectible 1930s Cathedral/Waterfall Tabletop Model
const meta = {
  name: 'Art Deco Radio',
  category: 'prop',
  role: 'prop'
};

async function build() {
  const root = createRoot('ArtDecoRadio');

  // Materials
  const walnutMat = gameMaterial(0x4a2a18, { roughness: 0.42, metalness: 0.06 });
  const darkWoodMat = gameMaterial(0x23140c, { roughness: 0.48, metalness: 0.04 });
  const brassMat = gameMaterial(0xd4af37, { roughness: 0.22, metalness: 0.88 });
  const antiqueBrassMat = gameMaterial(0x9e7b2c, { roughness: 0.35, metalness: 0.82 });
  const grilleClothMat = gameMaterial(0xc29b38, { roughness: 0.92, metalness: 0.02 });
  const dialFaceMat = gameMaterial(0xfcf5e5, { roughness: 0.55, emissive: 0xffd27d, emissiveIntensity: 0.32 });
  const dialGlassMat = glassMaterial(0xd8f0ff, { opacity: 0.32, roughness: 0.08 });
  const pointerMat = gameMaterial(0xd32f2f, { roughness: 0.30, metalness: 0.10 });
  const bakeliteMat = gameMaterial(0x1a120e, { roughness: 0.32, metalness: 0.08 });
  const pilotJewelMat = gameMaterial(0xdd1818, { roughness: 0.15, emissive: 0xff2200, emissiveIntensity: 0.75 });
  const backPanelMat = walnutMat;
  const dialTickMat = gameMaterial(0x2b1c11, { roughness: 0.6 });

  // 1. Stepped Plinth Base & Corner Feet
  const lowerPlinthGeo = await roundedBoxGeo(0.200, 0.015, 0.340, 0.004, { segments: 32 });
  createPart('LowerPlinth', lowerPlinthGeo, darkWoodMat, { position: [0, 0.0075, 0], parent: root });

  const plinthBrassGeo = boxGeo(0.194, 0.004, 0.330);
  createPart('PlinthBrassTrim', plinthBrassGeo, brassMat, { position: [0, 0.017, 0], parent: root });

  const upperPlinthGeo = await roundedBoxGeo(0.186, 0.014, 0.316, 0.0035, { segments: 32 });
  createPart('UpperPlinth', upperPlinthGeo, darkWoodMat, { position: [0, 0.026, 0], parent: root });

  const footPositions = [
    [0.075, 0.003, 0.140],
    [0.075, 0.003, -0.140],
    [-0.075, 0.003, 0.140],
    [-0.075, 0.003, -0.140]
  ];
  footPositions.forEach((pos, idx) => {
    const footGeo = cylinderYGeo(0.014, 0.011, 0.006, 32);
    createPart(`Foot_${idx + 1}`, footGeo, antiqueBrassMat, { position: pos, parent: root });
    const footRingGeo = cylinderYGeo(0.016, 0.016, 0.002, 32);
    createPart(`FootRing_${idx + 1}`, footRingGeo, brassMat, { position: [pos[0], 0.005, pos[2]], parent: root });
  });

  // 2. Stepped Silhouette Cabinet Body
  const wingGeo = await roundedBoxGeo(0.165, 0.200, 0.050, 0.014, { segments: 36 });
  createPart('LeftWing', wingGeo, walnutMat, { position: [0, 0.133, -0.125], parent: root });
  createPart('RightWing', wingGeo, walnutMat, { position: [0, 0.133, 0.125], parent: root });

  [-0.151, 0.151].forEach((zSide, sideIdx) => {
    [-0.03, 0, 0.03].forEach((yOffset, ribIdx) => {
      const ribGeo = cylinderXGeo(0.002, 0.002, 0.12, 16);
      createPart(`WingRib_${sideIdx}_${ribIdx}`, ribGeo, brassMat, {
        position: [0, 0.133 + yOffset, zSide],
        parent: root
      });
    });
  });

  const shoulderGeo = await roundedBoxGeo(0.172, 0.280, 0.026, 0.010, { segments: 36 });
  createPart('LeftShoulder', shoulderGeo, walnutMat, { position: [0, 0.173, -0.088], parent: root });
  createPart('RightShoulder', shoulderGeo, walnutMat, { position: [0, 0.173, 0.088], parent: root });

  // Reeded decorative wood pilasters on shoulders
  [-0.096, -0.088, -0.080, 0.080, 0.088, 0.096].forEach((zPos, pIdx) => {
    const reedGeo = cylinderYGeo(0.002, 0.002, 0.264, 16);
    createPart(`ShoulderReed_${pIdx}`, reedGeo, darkWoodMat, {
      position: [0.0865, 0.173, zPos],
      parent: root
    });
  });

  const centerTowerGeo = await roundedBoxGeo(0.178, 0.347, 0.150, 0.018, { segments: 42 });
  createPart('CenterTower', centerTowerGeo, walnutMat, { position: [0, 0.206, 0], parent: root });

  // Waterfall Top Brass Speed Ribbons
  [-0.038, 0, 0.038].forEach((zPos, rIdx) => {
    const topRibbonGeo = boxGeo(0.140, 0.003, 0.003);
    createPart(`WaterfallRibbon_${rIdx}`, topRibbonGeo, brassMat, {
      position: [0, 0.380, zPos],
      parent: root
    });
  });

  [-0.076, 0.076].forEach((zPos, idx) => {
    const pillarGeo = cylinderYGeo(0.0035, 0.0035, 0.276, 20);
    createPart(`DecoPillar_${idx + 1}`, pillarGeo, brassMat, { position: [0.088, 0.174, zPos], parent: root });
    const capGeo = boxGeo(0.010, 0.006, 0.010);
    createPart(`PillarCap_${idx + 1}`, capGeo, brassMat, { position: [0.088, 0.314, zPos], parent: root });
    const baseGeo = boxGeo(0.010, 0.006, 0.010);
    createPart(`PillarBase_${idx + 1}`, baseGeo, brassMat, { position: [0.088, 0.035, zPos], parent: root });
  });

  const crestTiers = [
    { size: [0.110, 0.005, 0.070], y: 0.382 },
    { size: [0.085, 0.005, 0.048], y: 0.387 },
    { size: [0.055, 0.005, 0.026], y: 0.392 }
  ];
  crestTiers.forEach((tier, idx) => {
    const tierGeo = boxGeo(tier.size[0], tier.size[1], tier.size[2]);
    createPart(`ApexCrest_${idx + 1}`, tierGeo, brassMat, { position: [0, tier.y, 0], parent: root });
  });

  // 3. Speaker Grille & Woven Geometric Fretwork
  // Open 4-piece stepped brass bezel frame around acoustic aperture (projects from X=0.088 to 0.096)
  const grilleFrameT = 0.008;
  const grilleTopBar = boxGeo(grilleFrameT, 0.010, 0.124);
  createPart('GrilleFrameTop', grilleTopBar, brassMat, { position: [0.092, 0.275 + 0.063, 0], parent: root });
  const grilleBotBar = boxGeo(grilleFrameT, 0.010, 0.124);
  createPart('GrilleFrameBot', grilleBotBar, brassMat, { position: [0.092, 0.275 - 0.063, 0], parent: root });
  const grilleLeftBar = boxGeo(grilleFrameT, 0.116, 0.010);
  createPart('GrilleFrameLeft', grilleLeftBar, brassMat, { position: [0.092, 0.275, -0.057], parent: root });
  const grilleRightBar = boxGeo(grilleFrameT, 0.116, 0.010);
  createPart('GrilleFrameRight', grilleRightBar, brassMat, { position: [0.092, 0.275, 0.057], parent: root });

  // Acoustic Fabric Backing (Woven golden cloth sitting cleanly in aperture at X = 0.0898)
  const clothGeo = boxGeo(0.002, 0.116, 0.104);
  createPart('GrilleCloth', clothGeo, grilleClothMat, { position: [0.0898, 0.275, 0], parent: root });

  // Woven cloth weave texture: interwoven vertical warp & horizontal weft bars
  [-0.045, -0.038, -0.031, -0.024, -0.017, -0.010, -0.003, 0.004, 0.011, 0.018, 0.025, 0.032, 0.039, 0.046].forEach((zPos, idx) => {
    const warpGeo = cylinderYGeo(0.0006, 0.0006, 0.114, 16);
    createPart(`GrilleWarp_${idx}`, warpGeo, darkWoodMat, { position: [0.0910, 0.275, zPos], parent: root });
  });

  [-0.050, -0.040, -0.030, -0.020, -0.010, 0, 0.010, 0.020, 0.030, 0.040, 0.050].forEach((yOff, idx) => {
    const weftGeo = cylinderZGeo(0.0006, 0.0006, 0.098, 16);
    createPart(`GrilleWeft_${idx}`, weftGeo, grilleClothMat, { position: [0.0916, 0.275 + yOff, 0], parent: root });
  });

  // Woven-look Chevron Fretwork in front of fabric
  const chevronTiers = [0.038, 0.014, -0.010, -0.034];
  chevronTiers.forEach((yOff, cIdx) => {
    const armGeoL = boxGeo(0.002, 0.0035, 0.048);
    createPart(`Chevron_L_${cIdx}`, armGeoL, darkWoodMat, {
      position: [0.0926, 0.275 + yOff, -0.024],
      rotation: [22, 0, 0],
      parent: root
    });
    const armGeoR = boxGeo(0.002, 0.0035, 0.048);
    createPart(`Chevron_R_${cIdx}`, armGeoR, darkWoodMat, {
      position: [0.0926, 0.275 + yOff, 0.024],
      rotation: [-22, 0, 0],
      parent: root
    });
  });

  // Vertical brass speedbars over the chevron fretwork
  [-0.022, 0, 0.022].forEach((zPos, idx) => {
    const barGeo = cylinderYGeo(0.0018, 0.0018, 0.114, 16);
    createPart(`GrilleCenterBar_${idx}`, barGeo, brassMat, { position: [0.0938, 0.275, zPos], parent: root });
  });

  // Brass Diamond Medallion in center of grille
  const medallionGeo = boxGeo(0.0035, 0.018, 0.018);
  createPart('GrilleMedallion', medallionGeo, brassMat, { position: [0.0948, 0.275, 0], rotation: [45, 0, 0], parent: root });

  // 4. Inset Glass Tuning Dial & Animated Pointer
  // Stepped brass bezel frame projecting from X = 0.089 to 0.098
  const dialFrameT = 0.009;
  const dialTopBar = boxGeo(dialFrameT, 0.010, 0.114);
  createPart('DialFrameTop', dialTopBar, brassMat, { position: [0.0935, 0.165 + 0.028, 0], parent: root });
  const dialBotBar = boxGeo(dialFrameT, 0.010, 0.114);
  createPart('DialFrameBot', dialBotBar, brassMat, { position: [0.0935, 0.165 - 0.028, 0], parent: root });
  const dialLeftBar = boxGeo(dialFrameT, 0.046, 0.011);
  createPart('DialFrameLeft', dialLeftBar, brassMat, { position: [0.0935, 0.165, -0.051], parent: root });
  const dialRightBar = boxGeo(dialFrameT, 0.046, 0.011);
  createPart('DialFrameRight', dialRightBar, brassMat, { position: [0.0935, 0.165, 0.051], parent: root });

  // Recessed Illuminated Dial Face Backplate (sitting cleanly at X = 0.0902)
  const dialFaceGeo = boxGeo(0.002, 0.046, 0.090);
  createPart('DialFace', dialFaceGeo, dialFaceMat, { position: [0.0902, 0.165, 0], parent: root });

  // Dial Frequency Scale Markings (crisp station bands)
  const scaleLineAM = boxGeo(0.001, 0.0018, 0.076);
  createPart('ScaleLineAM', scaleLineAM, dialTickMat, { position: [0.0912, 0.176, 0], parent: root });

  const scaleLineSW = boxGeo(0.001, 0.0018, 0.076);
  createPart('ScaleLineSW', scaleLineSW, dialTickMat, { position: [0.0912, 0.154, 0], parent: root });

  for (let t = -8; t <= 8; t++) {
    const isMajor = t % 2 === 0;
    const tickH = isMajor ? 0.006 : 0.0035;
    const tickGeo = boxGeo(0.001, tickH, 0.0012);
    createPart(`DialTick_${t + 8}`, tickGeo, dialTickMat, {
      position: [0.0912, 0.176 - (isMajor ? 0.0025 : 0.001), t * 0.0044],
      parent: root
    });
  }

  // Animated Tuning Pointer (mounted on Joint_TuningPointer, swinging at X = 0.0924)
  const pointerPivot = createPivot('TuningPointer', [0.0924, 0.144, 0], root);

  const needleArmGeo = boxGeo(0.0014, 0.034, 0.0018);
  createPart('NeedleArm', needleArmGeo, pointerMat, { position: [0, 0.017, 0], parent: pointerPivot });

  const needleTipGeo = cylinderYGeo(0.0006, 0.0018, 0.006, 12);
  createPart('NeedleTip', needleTipGeo, pointerMat, { position: [0, 0.034, 0], parent: pointerPivot });

  const pointerHubGeo = cylinderXGeo(0.004, 0.004, 0.0025, 24);
  createPart('NeedleHub', pointerHubGeo, brassMat, { position: [0, 0, 0], parent: pointerPivot });

  // Protective Inset Dial Glass (recessed inside bezel at X = 0.0945)
  const glassGeo = boxGeo(0.0015, 0.046, 0.090);
  createPart('DialGlass', glassGeo, dialGlassMat, { position: [0.0945, 0.165, 0], parent: root });

  // 5. Tactile Differentiated Knobs
  // Center Tuning Knob (with 18 flutes and brass cap, animated on Joint_TuningKnob)
  const tuningKnobPivot = createPivot('TuningKnob', [0.092, 0.076, 0], root);

  const centerBezelGeo = cylinderXGeo(0.017, 0.017, 0.003, 28);
  createPart('TuningKnobBezel', centerBezelGeo, brassMat, { position: [0.0015, 0, 0], parent: tuningKnobPivot });

  const centerBodyGeo = cylinderXGeo(0.0145, 0.0155, 0.014, 28);
  createPart('TuningKnobBody', centerBodyGeo, bakeliteMat, { position: [0.008, 0, 0], parent: tuningKnobPivot });

  const fluteCount = 24;
  for (let f = 0; f < fluteCount; f++) {
    const angle = (f * (360 / fluteCount)) * (Math.PI / 180);
    const fluteGeo = cylinderXGeo(0.0013, 0.0013, 0.012, 14);
    createPart(`TuningFlute_${f}`, fluteGeo, bakeliteMat, {
      position: [0.008, 0.0152 * Math.cos(angle), 0.0152 * Math.sin(angle)],
      parent: tuningKnobPivot
    });
  }

  const centerCapGeo = cylinderXGeo(0.009, 0.009, 0.002, 28);
  createPart('TuningCap', centerCapGeo, brassMat, { position: [0.015, 0, 0], parent: tuningKnobPivot });

  const tuningPipGeo = boxGeo(0.002, 0.003, 0.0015);
  createPart('TuningPip', tuningPipGeo, pointerMat, { position: [0.0158, 0.006, 0], parent: tuningKnobPivot });

  // Left Knob: Dual-Concentric Volume / Tone Knob
  const leftKnobBaseGeo = cylinderXGeo(0.013, 0.014, 0.008, 24);
  createPart('VolumeKnobBase', leftKnobBaseGeo, darkWoodMat, { position: [0.094, 0.076, -0.054], parent: root });

  const leftKnobBrassRim = cylinderXGeo(0.0142, 0.0142, 0.0025, 24);
  createPart('VolumeKnobRim', leftKnobBrassRim, brassMat, { position: [0.0985, 0.076, -0.054], parent: root });

  const leftKnobInnerGeo = cylinderXGeo(0.0075, 0.008, 0.015, 20);
  createPart('VolumeKnobInner', leftKnobInnerGeo, bakeliteMat, { position: [0.103, 0.076, -0.054], parent: root });

  const leftKnobCapGeo = cylinderXGeo(0.005, 0.005, 0.002, 20);
  createPart('VolumeKnobCap', leftKnobCapGeo, brassMat, { position: [0.111, 0.076, -0.054], parent: root });

  // Right Knob: Art Deco Teardrop Band Selector Knob
  const rightKnobHubGeo = cylinderXGeo(0.012, 0.0125, 0.009, 24);
  createPart('SelectorKnobHub', rightKnobHubGeo, bakeliteMat, { position: [0.094, 0.076, 0.054], parent: root });

  const rightPointerArm = boxGeo(0.007, 0.016, 0.005);
  createPart('SelectorPointerArm', rightPointerArm, bakeliteMat, {
    position: [0.097, 0.082, 0.058],
    rotation: [30, 0, 0],
    parent: root
  });

  const rightKnobCap = cylinderXGeo(0.006, 0.006, 0.002, 20);
  createPart('SelectorKnobCap', rightKnobCap, brassMat, { position: [0.101, 0.076, 0.054], parent: root });

  // 6. Fine Details
  const lampBezelGeo = cylinderXGeo(0.0055, 0.0055, 0.003, 16);
  createPart('PilotLampBezel', lampBezelGeo, brassMat, { position: [0.090, 0.114, 0], parent: root });

  const jewelGeo = cylinderXGeo(0.0035, 0.002, 0.003, 14);
  createPart('PilotJewel', jewelGeo, pilotJewelMat, { position: [0.092, 0.114, 0], parent: root });

  const plaqueGeo = boxGeo(0.002, 0.009, 0.042);
  createPart('BrandPlaque', plaqueGeo, brassMat, { position: [0.090, 0.048, 0], parent: root });

  const plaqueInlayGeo = boxGeo(0.001, 0.006, 0.036);
  createPart('BrandPlaqueInlay', plaqueInlayGeo, darkWoodMat, { position: [0.0912, 0.048, 0], parent: root });

  // Center rear panel fitting stepped cabinet silhouette
  const backBoardGeo = boxGeo(0.004, 0.298, 0.112);
  createPart('BackPanel', backBoardGeo, backPanelMat, { position: [-0.089, 0.1995, 0], parent: root });

  // Wing rear panels matching stepped flanks
  [-0.125, 0.125].forEach((zPos, idx) => {
    const wingBackGeo = boxGeo(0.004, 0.162, 0.020);
    createPart(`WingBack_${idx}`, wingBackGeo, backPanelMat, { position: [-0.0825, 0.133, zPos], parent: root });
  });

  for (let v = 0; v < 5; v++) {
    const louverGeo = boxGeo(0.002, 0.005, 0.100);
    createPart(`BackLouver_${v}`, louverGeo, darkWoodMat, { position: [-0.092, 0.230 - v * 0.018, 0], parent: root });
  }

  const grommetGeo = cylinderXGeo(0.006, 0.006, 0.004, 16);
  createPart('PowerGrommet', grommetGeo, bakeliteMat, { position: [-0.092, 0.062, 0.040], parent: root });

  return root;
}

function animate(root) {
  const pointerTrack = rotationTrack('Joint_TuningPointer', [
    { time: 0.0, rotation: [-24, 0, 0] },
    { time: 1.2, rotation: [10, 0, 0] },
    { time: 2.2, rotation: [26, 0, 0] },
    { time: 3.0, rotation: [-8, 0, 0] },
    { time: 4.0, rotation: [-24, 0, 0] }
  ]);

  const knobTrack = rotationTrack('Joint_TuningKnob', [
    { time: 0.0, rotation: [0, 0, 0] },
    { time: 1.2, rotation: [240, 0, 0] },
    { time: 2.2, rotation: [480, 0, 0] },
    { time: 3.0, rotation: [160, 0, 0] },
    { time: 4.0, rotation: [0, 0, 0] }
  ]);

  return [createClip('Tune', 4.0, [pointerTrack, knobTrack])];
}

Brief and retained revisions

Brief summary

Create a collectible Art Deco radio with a rounded walnut cabinet, brass trim, a geometric speaker grille, an inset tuning dial and animated controls.

  1. Initial design

    First retained radio. Solid bezel faces obscured the dial and grille, and several decorative bars extended beyond the cabinet.

    Download initial design source

    SHA-256: f2989a63a016b89ed7dc0704537b33c3dda9969f59ee0b759ddff3e620c8b96b

  2. Frame and cabinet repair

    Opened the bezel frames, contained the grille bars and fitted the rear panels to the stepped cabinet.

    Download frame and cabinet repair source

    SHA-256: 98e5e0acc662589323030271bc1cf44987890c33c4228ad1bd3f1d0a7cea1d49

  3. Dial and grille revision

    Moved the dial and grille layers in front of the cabinet surface and added fluting to the controls and shoulders.

    Download dial and grille revision source

    SHA-256: ce748f8b92d155134d6f06938e17d189663418f16d2c0a09afa05ab5cdf80c52

  4. Final Gemini authoring revision

    Added woven grille bars, detailed feet and finer tuning-knob flutes. The tuning scale uses marks rather than numeric labels.

    Download final gemini authoring revision source

    SHA-256: d79eec971bd3199993b8af63673f17feb0b968d91745873ad032927ea48a9241

  5. Maintainer rear-panel fit and finish · Shown here

    Codex maintainer agent resized the three rear panels to stay inside the flat cabinet faces, matched their walnut material, and repositioned the louvers and power grommet. Actual front and rear GPU views inspected. Original dial and control animation retained.

    Download maintainer rear-panel fit and finish source

    SHA-256: f0c0ec0dee84e5b8714744a16f8e66399ad66f35a415ad974c409efed4b7bf73