<!-- RUBY-BACKUP · part 529 -->
 if(sceneRef) sceneRef.add(g); },
      undo: function(){ if(sceneRef) sceneRef.remove(g); }
    });
    codeStatus('creative streets laid');
    // floor comes WITH the highways — every build, no exceptions
    try{
      if(typeof buildFloorMesh==='function' && (typeof floorMesh==='undefined' || !floorMesh)){
        buildFloorMesh();
      }
    }catch(e){}
    // signs are BORN on the highways — permanently fixed to the streets
    try{ if(typeof buildHighwaySigns==='function') buildHighwaySigns(g); }catch(e){}
  }catch(e){ codeStatus('streets failed'); }
}
/* OBJ EXPORT — share what you built */
function exportFBX(){
  try{
    var target = window._highlighted || window._selectedBlock;
    if(!target){ codeStatus('tap a block first, then export'); return; }
    var output = '; FBX 7.4.0 project file\n';
    output += '; Exported from the Creator — for the ancestors\n';
    output += 'FBXHeaderExtension:  {\n';
    output += '    FBXHeaderVersion: 1003\n';
    output += '    FBXVersion: 7400\n';
    output += '    CreationTimeStamp:  {\n';
    output += '        Year: 2026\n';
    output += '    }\n';
    output += '    Creator: "Solid Creator"\n';
    output += '}\n';
    output += 'Definitions:  {\n';
    output += '    Version: 100\n';
    output += '    Count: 1\n';
    output += '    ObjectType: "Model" {\n';
    output += '        Count: 1\n';
    output += '    }\n';
    output += '}\n';
    output += 'Objects:  {\n';
    var vOffset = 0;
    var meshIdx = 0;
    target.updateMatrixWorld(true);
    target.traverse(function(m){
      if(m.isMesh && m.geometry){
        var geo = m.geometry;
        var pos = geo.attributes.position;
        var idx = geo.index;
        output += '    Model: "Model::mesh' + meshIdx + '", "Mesh" {\n';
        output += '        Version: 232\n';
        /* vertices */
        output += '        Vertices: ';
        var v = new THREE.Vector3();
        var verts = [];
        for(var i=0; i<pos.count; i++){
          v.set(pos.getX(i), pos.getY(i), pos.getZ(i));
          m.localToWorld(v);
          verts.push(v.x.toFixed(4) + ',' + v.y.toFixed(4) + ',' + v.z.toFixed(4));
        }
        output += verts.join(',') + '\n';
        /* polygon indices */
        output += '        PolygonVertexIndex: ';
        var polys = [];
        if(idx){
          for(var f=0; f<idx.count; f+=3){
            polys.push(idx.getX(f), idx.getX(f+1), -idx.getX(f+2)-1);
          }
        }else{
          for(var f2=0; f2<pos.count; f2+=3){
            polys.push(f2, f2+1, -f2-2-1);
          }
        }
        output += polys.join(',') + '\n';
        output += '        GeometryVersion: 124\n';
        output += '    }\n';
        meshIdx++;
      }
    });
    output += '}\n';
    var blob = new Blob([output], {type:'text/plain'});
    var url = URL.createObjectURL(blob);
    var a = document.createElement('a');
    a.href = url;
    a.download = 'creator-model.fbx';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
    codeStatus('exported FBX — share it');
  }catch(e){ codeStatus('FBX export failed'); }
}
function exportOBJ(){
  try{
    var target = window._highlighted || window._selectedBlock;
    if(!target){ codeStatus('tap a block first, then export'); return; }
    var output = '# Exported from the Creator\n';
    output += '# For the ancestors\n';
    var vOffset = 0;
    target.updateMatrixWorld(true);
    target.traverse(function(m){
      if(m.isMesh && m.geometry){
        var geo = m.geometry;
        var pos = geo.attributes.position;
        var norm = geo.attributes.normal;
        var idx = geo.index;
        // vertices (world space)
        var v = new THREE.Vector3();
        for(var i=0; i<pos.count; i++){
          v.set(pos.getX(i), pos.getY(i), pos.getZ(i));
          m.localToWorld(v);
          output += 'v ' + v.x.toFixed(4) + ' ' + v.y.toFixed(4) + ' ' + v.z.toFixed(4) + '\n';
        }
        // normals
        if(norm){
          for(var n=0; n<norm.count; n++){
            output += 'vn ' + norm.getX(n).toFixed(4) + ' ' + norm.getY(n).toFixed(4) + ' ' + norm.getZ(n).toFixed(4) + '\n';
          }
        }
        // faces
        if(idx){
          for(var f=0; f<idx.count; f+=3){
            var a = idx.getX(f)+1+vOffset, b = idx.getX(f+1)+1+vOffset, d = idx.getX(f+2)+1+vOffset;
            output += 'f ' + a + '//' + a + ' ' + b + '//' + b + ' ' + d + '//' + d + '\n';
          }
        }else{
          for(var f2=0; f2<pos.count; f2+=3){
            var a2 = f2+1+vOffset, b2 = f2+1+1+vOffset, d2 = f2+1+2+vOffset;
            output += 'f ' + a2 + '//' + a2 + ' ' + b2 + '//' + b2 + ' ' + d2 + '//' + d2 + '\n';
          }
        }
        vOffset += pos.count;
      }
    });
    // download
    var blob = new Blob([output], {type:'text/plain'});
    var url = URL.createObjectURL(blob);
    var a = document.createElement('a');
    a.href = url;
   