← WebMCP Directory

Tool tree

3dstreet.app

Productivity & BusinessTools verified
Website
3DStreet
Explore capabilities
    componentAddAction

    Add an A-Frame component to an entity with an optional initial value (e.g. component 'animation__spin', value 'property: rotation; to: 0 360 0; loop: true; dur: 4000'). Use entityUpdate to change a component the entity already has, and managedStreetUpdate for street-segment generated components.

    View tool JSON
    {
      "name": "componentAdd",
      "kind": "act",
      "impl": "imperative",
      "description": "Add an A-Frame component to an entity with an optional initial value (e.g. component 'animation__spin', value 'property: rotation; to: 0 360 0; loop: true; dur: 4000'). Use entityUpdate to change a component the entity already has, and managedStreetUpdate for street-segment generated components.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "The ID of the entity to add the component to"
          },
          "component": {
            "type": "string",
            "description": "The component name, including a multi-instance suffix when several of the same type are wanted (e.g. 'animation__spin')"
          },
          "value": {
            "type": "string",
            "description": "Initial component value as an A-Frame attribute string ('prop: v; prop2: v2'); omit for component defaults"
          }
        },
        "required": [
          "entityId",
          "component"
        ]
      }
    }
    componentRemoveAction

    Remove an A-Frame component from an entity. Undoable — the removed value is restored on undo.

    View tool JSON
    {
      "name": "componentRemove",
      "kind": "act",
      "impl": "imperative",
      "description": "Remove an A-Frame component from an entity. Undoable — the removed value is restored on undo.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "The ID of the entity to remove the component from"
          },
          "component": {
            "type": "string",
            "description": "The component name as it appears on the entity (e.g. 'animation__spin')"
          }
        },
        "required": [
          "entityId",
          "component"
        ]
      }
    }
    detachAllClonesAction

    Detach every clone a generator (street-generated-clones, street-generated-stencil or street-generated-pedestrians component on a managed street segment) currently places, so each vehicle, tree, prop, stencil or pedestrian becomes a plain entity that can be moved, rotated, duplicated or deleted on its own, and remove that generator from the segment so nothing regenerates. The rest of the street stays managed. Use detachClone for a single object and convertStreetToShapes for the whole street. Name the generator by the segment entity and the component name on it; segments list their generators as 'street-generated-*' components in the scene state.

    View tool JSON
    {
      "name": "detachAllClones",
      "kind": "act",
      "impl": "imperative",
      "description": "Detach every clone a generator (street-generated-clones, street-generated-stencil or street-generated-pedestrians component on a managed street segment) currently places, so each vehicle, tree, prop, stencil or pedestrian becomes a plain entity that can be moved, rotated, duplicated or deleted on its own, and remove that generator from the segment so nothing regenerates. The rest of the street stays managed. Use detachClone for a single object and convertStreetToShapes for the whole street. Name the generator by the segment entity and the component name on it; segments list their generators as 'street-generated-*' components in the scene state.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "segmentId": {
            "type": "string",
            "description": "ID of the street-segment entity carrying the generator"
          },
          "component": {
            "type": "string",
            "description": "Generator component name on that segment, e.g. 'street-generated-clones__1', 'street-generated-stencil__1' or 'street-generated-pedestrians__1'"
          }
        },
        "required": [
          "segmentId",
          "component"
        ]
      }
    }
    detachCloneAction

    Detach one generated clone (a vehicle, tree, prop, stencil or pedestrian placed by a street-generated-clones, street-generated-stencil or street-generated-pedestrians component on a managed street segment) from its generator so it becomes a plain entity that can be moved, rotated, duplicated or deleted on its own; the rest of the segment stays generated. Name the clone by the segment entity, the generator component on it and the clone slot index (0-based creation order from the start of the segment; a slot already detached has no clone, and the generator's skip array lists the detached placements as 'x z' keys), or omit all three to detach the currently selected clone. Optional position/rotation place the detached entity.

    View tool JSON
    {
      "name": "detachClone",
      "kind": "act",
      "impl": "imperative",
      "description": "Detach one generated clone (a vehicle, tree, prop, stencil or pedestrian placed by a street-generated-clones, street-generated-stencil or street-generated-pedestrians component on a managed street segment) from its generator so it becomes a plain entity that can be moved, rotated, duplicated or deleted on its own; the rest of the segment stays generated. Name the clone by the segment entity, the generator component on it and the clone slot index (0-based creation order from the start of the segment; a slot already detached has no clone, and the generator's skip array lists the detached placements as 'x z' keys), or omit all three to detach the currently selected clone. Optional position/rotation place the detached entity.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "segmentId": {
            "type": "string",
            "description": "ID of the street-segment entity carrying the generator"
          },
          "component": {
            "type": "string",
            "description": "Generator component name on that segment, e.g. 'street-generated-clones__1', 'street-generated-stencil__1' or 'street-generated-pedestrians__1'"
          },
          "slotIndex": {
            "type": "number",
            "description": "0-based slot of the clone in the generator creation order along the segment"
          },
          "position": {
            "type": "string",
            "description": "Optional \"x y z\" segment-local position for the detached entity (default: where the clone is)"
          },
          "rotation": {
            "type": "string",
            "description": "Optional \"x y z\" rotation in degrees for the detached entity (default: the clone rotation)"
          }
        },
        "required": []
      }
    }
    entityCloneAction

    Clone an entity (including its children) and insert the copy as its next sibling. Returns with the clone selected; read getSelectedEntity for the new id.

    View tool JSON
    {
      "name": "entityClone",
      "kind": "act",
      "impl": "imperative",
      "description": "Clone an entity (including its children) and insert the copy as its next sibling. Returns with the clone selected; read getSelectedEntity for the new id.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "The ID of the entity to clone"
          }
        },
        "required": [
          "entityId"
        ]
      }
    }
    entityCreateAction

    Create a new entity in the A-Frame scene with specified components and transforms

    View tool JSON
    {
      "name": "entityCreate",
      "kind": "act",
      "impl": "imperative",
      "description": "Create a new entity in the A-Frame scene with specified components and transforms",
      "inputSchema": {
        "type": "object",
        "properties": {
          "mixin": {
            "type": "string",
            "description": "The mixin id value for the new entity (e.g., \"box-truck-rig\")"
          },
          "position": {
            "type": "string",
            "description": "Position as space-separated x y z values (e.g., \"0 1.5 -3\") default 0 0 0"
          },
          "rotation": {
            "type": "string",
            "description": "Rotation as space-separated x y z values in degrees (e.g., \"0 45 0\") default 0 0 0"
          },
          "scale": {
            "type": "string",
            "description": "Scale as space-separated x y z values (e.g., \"2 2 2\") default 1 1 1"
          }
        },
        "required": []
      }
    }
    entityRemoveAction

    Remove an entity from the scene. Undoable via the undo tool.

    View tool JSON
    {
      "name": "entityRemove",
      "kind": "act",
      "impl": "imperative",
      "description": "Remove an entity from the scene. Undoable via the undo tool.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "The ID of the entity to remove"
          }
        },
        "required": [
          "entityId"
        ]
      }
    }
    entityUpdateAction

    Update an entity in the A-Frame scene with new properties or components

    View tool JSON
    {
      "name": "entityUpdate",
      "kind": "act",
      "impl": "imperative",
      "description": "Update an entity in the A-Frame scene with new properties or components",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "The ID of the entity to update"
          },
          "component": {
            "type": "string",
            "description": "The component to update (e.g., position, rotation, mixin)"
          },
          "property": {
            "type": "string",
            "description": "The property to update within the component (optional)"
          },
          "value": {
            "type": "string",
            "description": "The new value to set"
          },
          "expressionForValue": {
            "type": "string",
            "description": "Mathematical expression to evaluate for the value (e.g., \"5 - 2\"). Use this instead of value when calculation is needed."
          }
        },
        "required": [
          "entityId",
          "component"
        ]
      }
    }
    updateSceneTitleAction

    Update the scene title in the global state

    View tool JSON
    {
      "name": "updateSceneTitle",
      "kind": "act",
      "impl": "imperative",
      "description": "Update the scene title in the global state",
      "inputSchema": {
        "type": "object",
        "properties": {
          "value": {
            "type": "string",
            "description": "The new scene title"
          }
        },
        "required": [
          "value"
        ]
      }
    }
    managedStreetCreateAction

    Create a new managed street from a cross-section (array of segments, listed from one edge to the other). If the scene has geographic context (setLatLon / Google 3D Tiles), the tiles already supply the surroundings: do NOT add boundary segments, buildings or other land-use models unless the user explicitly asks for synthetic surroundings — the cross-section should normally begin and end with sidewalks. For each segment, omit surface/color/elevation/direction/generated to receive the type's preset — the same content a user gets by picking that type in the sidebar (e.g. bike-lane → green asphalt, bike-arrow stencils, cyclists; bus-lane → BUS ONLY stencil, buses; sidewalk → pedestrians). Call listSegmentPresets to see them. Only supply `generated` to override a preset. Returns entityId, width, presetsApplied, warnings and a readBack of what actually mounted.

    View tool JSON
    {
      "name": "managedStreetCreate",
      "kind": "act",
      "impl": "imperative",
      "description": "Create a new managed street from a cross-section (array of segments, listed from one edge to the other). If the scene has geographic context (setLatLon / Google 3D Tiles), the tiles already supply the surroundings: do NOT add boundary segments, buildings or other land-use models unless the user explicitly asks for synthetic surroundings — the cross-section should normally begin and end with sidewalks. For each segment, omit surface/color/elevation/direction/generated to receive the type's preset — the same content a user gets by picking that type in the sidebar (e.g. bike-lane → green asphalt, bike-arrow stencils, cyclists; bus-lane → BUS ONLY stencil, buses; sidewalk → pedestrians). Call listSegmentPresets to see them. Only supply `generated` to override a preset. Returns entityId, width, presetsApplied, warnings and a readBack of what actually mounted.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the street configuration"
          },
          "length": {
            "type": "string",
            "description": "Length of the street in meters (default: 60)"
          },
          "position": {
            "type": "string",
            "description": "Position as space-separated x y z values (e.g., \"0 0 0\")"
          },
          "segments": {
            "type": "array",
            "description": "Array of segment definitions for the street",
            "items": {
              "type": "object",
              "description": "Segment definition",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Display name of the segment"
                },
                "type": {
                  "type": "string",
                  "description": "Type of segment. Valid values: \"drive-lane\", \"bike-lane\", \"sidewalk\", \"parking-lane\", \"divider\", \"grass\", \"rail\", \"bus-lane\", \"boundary\". \"boundary\" is SYNTHETIC flanking land use (buildings, waterfront, fences) for scenes without geographic context — it renders outside the travelled way at the street edge and auto-tiles models edge-to-edge (`variant` + `side`, no `generated` needed). Do not add boundaries when the scene has a location: the Google 3D Tiles already show the real surroundings and synthetic buildings would overlap them."
                },
                "surface": {
                  "type": "string",
                  "description": "Surface material (e.g., \"asphalt\", \"concrete\", \"grass\", \"sidewalk\", \"gravel\", \"sand\", \"planting-strip\", \"none\", \"solid\"). Optional for building segments — the variant supplies a sensible default. For hatched dividers use `generated.striping` with `striping: \"hatched\"` instead of a surface."
                },
                "color": {
                  "type": "string",
                  "description": "Hex color code (e.g., \"#ffffff\")"
                },
                "elevation": {
                  "type": "number",
                  "description": "Vertical offset in meters (0 = road level, 0.15 = curb/sidewalk height). Negative values are not supported."
                },
                "width": {
                  "type": "number",
                  "description": "Width in meters"
                },
                "direction": {
                  "type": "string",
                  "description": "Traffic direction (\"none\", \"inbound\", \"outbound\")"
                },
                "variant": {
                  "type": "string",
                  "description": "Variant preset for `type: \"boundary\"` segments. Valid values: \"brownstone\" (urban mixed-use SM3D blocks), \"suburban\" (detached single-family houses), \"arcade\" (arched street-front buildings), \"water\" (seawall), \"grass\" (fenced grass strip), \"parking\" (fenced parking lot), \"sp-mixeduse\" (StreetPlan mixed-use), \"sp-residential\" (StreetPlan single-family/townhouse), \"sp-big-box\" (StreetPlan big-box stores), \"custom\" (preserve existing settings). Setting variant on a boundary segment auto-fits the model array; do NOT pass `generated.clones` for boundaries unless you want full control. Only meaningful when `type: \"boundary\"`, and only for scenes without geographic context (see `type`)."
                },
                "side": {
                  "type": "string",
                  "description": "Side of the street the segment sits on. Required for `type: \"boundary\"` (controls placement outside the travelled way edge and which direction the models face). Valid values: \"left\", \"right\". Frame of reference is the street's own cross-section, not the camera: \"left\" is the inbound side and \"right\" the outbound side (right-hand-drive convention; swap for left-hand-drive countries). segments[0] sits at the first edge; getGeoContext reports the compass bearing of each edge.",
                  "enum": [
                    "left",
                    "right"
                  ]
                },
                "generated": {
                  "type": "object",
                  "description": "Optional generated content — omit to receive the type preset. Two different systems: `clones` places 3D models (vehicles, cyclists, trees, lamps, furniture — any listMixins id with generator \"clones\"); `stencil` paints flat road markings (arrows, sharrows, words like BUS ONLY — only ids with generator \"stencil\"). Never put a vehicle in `stencil` or a marking in `clones`.",
                  "properties": {
                    "clones": {
                      "type": "array",
                      "description": "Clones configuration for repeated 3D models",
                      "items": {
                        "type": "object",
                        "properties": {
                          "mode": {
                            "type": "string",
                            "description": "Clone mode (\"random\", \"fixed\", \"single\")"
                          },
                          "modelsArray": {
                            "type": "string",
                            "description": "Comma-separated 3D model ids from listMixins (generator \"clones\"), e.g. \"sedan-rig, box-truck-rig\" or \"bus\". Unknown ids are rejected."
                          },
                          "spacing": {
                            "type": "number",
                            "description": "Distance between models in meters"
                          },
                          "count": {
                            "type": "number",
                            "description": "Number of models (for random mode)"
                          },
                          "facing": {
                            "type": "number",
                            "description": "Rotation in degrees"
                          },
                          "randomFacing": {
                            "type": "boolean",
                            "description": "Random rotation"
                          },
                          "cycleOffset": {
                            "type": "number",
                            "description": "Offset in the repeating pattern (0-1)"
                          }
                        },
                        "required": [
                          "mode",
                          "modelsArray",
                          "spacing"
                        ]
                      }
                    },
                    "stencil": {
                      "type": "array",
                      "description": "Stencil configuration for road markings",
                      "items": {
                        "type": "object",
                        "properties": {
                          "modelsArray": {
                            "type": "string",
                            "description": "Comma-separated painted-marking ids (generator \"stencil\"), e.g. \"bike-arrow\", \"sharrow\", \"word-bus, word-only\". Unknown ids are rejected — use listMixins."
                          },
                          "spacing": {
                            "type": "number",
                            "description": "Distance between stencils"
                          },
                          "padding": {
                            "type": "number",
                            "description": "Edge padding"
                          },
                          "cycleOffset": {
                            "type": "number",
                            "description": "Pattern offset (0-1)"
                          },
                          "direction": {
                            "type": "string",
                            "description": "Stencil orientation"
                          },
                          "stencilHeight": {
                            "type": "number",
                            "description": "Height of stencil"
                          }
                        },
                        "required": [
                          "modelsArray",
                          "spacing"
                        ]
                      }
                    },
                    "pedestrians": {
                      "type": "array",
                      "description": "Pedestrian configuration",
                      "items": {
                        "type": "object",
                        "properties": {
                          "density": {
                            "type": "string",
                            "description": "Pedestrian density (\"normal\", \"dense\")"
                          }
                        },
                        "required": [
                          "density"
                        ]
                      }
                    },
                    "striping": {
                      "type": "array",
                      "description": "Striping configuration for lane markings",
                      "items": {
                        "type": "object",
                        "properties": {
                          "striping": {
                            "type": "string",
                            "description": "Stripe pattern type"
                          },
                          "side": {
                            "type": "string",
                            "description": "Side of segment (\"left\", \"right\")"
                          }
                        },
                        "required": [
                          "striping"
                        ]
                      }
                    }
                  }
                }
              },
              "required": [
                "type",
                "surface",
                "color",
                "elevation",
                "width",
                "direction"
              ]
            }
          }
        },
        "required": [
          "segments"
        ]
      }
    }
    managedStreetUpdateAction

    Update segments in an existing managed street (use entityUpdate for updating street properties)

    View tool JSON
    {
      "name": "managedStreetUpdate",
      "kind": "act",
      "impl": "imperative",
      "description": "Update segments in an existing managed street (use entityUpdate for updating street properties)",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "The ID of the managed street entity to update"
          },
          "operation": {
            "type": "string",
            "description": "Operation to perform (\"add-segment\", \"update-segment\", \"remove-segment\")"
          },
          "segmentIndex": {
            "type": "number",
            "description": "Index of the segment to update or remove (for update-segment and remove-segment operations)"
          },
          "segment": {
            "type": "object",
            "description": "Segment definition. For add-segment, \"type\" is required; other fields fall back to defaults if omitted. For update-segment, supply only the fields you want to change — omitted fields are left untouched.",
            "properties": {
              "name": {
                "type": "string",
                "description": "Display name of the segment"
              },
              "type": {
                "type": "string",
                "description": "Type of segment. Valid values: \"drive-lane\", \"bike-lane\", \"sidewalk\", \"parking-lane\", \"divider\", \"grass\", \"rail\", \"bus-lane\", \"boundary\". \"boundary\" is SYNTHETIC flanking land use (buildings, waterfront, fences) for scenes without geographic context — it renders outside the travelled way at the street edge and auto-tiles models edge-to-edge (`variant` + `side`, no `generated` needed). Do not add boundaries when the scene has a location: the Google 3D Tiles already show the real surroundings and synthetic buildings would overlap them."
              },
              "surface": {
                "type": "string",
                "description": "Surface material (e.g., \"asphalt\", \"concrete\", \"grass\", \"sidewalk\", \"gravel\", \"sand\", \"planting-strip\", \"none\", \"solid\"). Optional for building segments — the variant supplies a sensible default. For hatched dividers use `generated.striping` with `striping: \"hatched\"` instead of a surface."
              },
              "color": {
                "type": "string",
                "description": "Hex color code (e.g., \"#ffffff\")"
              },
              "elevation": {
                "type": "number",
                "description": "Vertical offset in meters (0 = road level, 0.15 = curb/sidewalk height). Negative values are not supported."
              },
              "width": {
                "type": "number",
                "description": "Width in meters"
              },
              "direction": {
                "type": "string",
                "description": "Traffic direction (\"none\", \"inbound\", \"outbound\")"
              },
              "variant": {
                "type": "string",
                "description": "Variant preset for `type: \"boundary\"` segments. Valid values: \"brownstone\" (urban mixed-use SM3D blocks), \"suburban\" (detached single-family houses), \"arcade\" (arched street-front buildings), \"water\" (seawall), \"grass\" (fenced grass strip), \"parking\" (fenced parking lot), \"sp-mixeduse\" (StreetPlan mixed-use), \"sp-residential\" (StreetPlan single-family/townhouse), \"sp-big-box\" (StreetPlan big-box stores), \"custom\" (preserve existing settings). Setting variant on a boundary segment auto-fits the model array; do NOT pass `generated.clones` for boundaries unless you want full control. Only meaningful when `type: \"boundary\"`, and only for scenes without geographic context (see `type`)."
              },
              "side": {
                "type": "string",
                "description": "Side of the street the segment sits on. Required for `type: \"boundary\"` (controls placement outside the travelled way edge and which direction the models face). Valid values: \"left\", \"right\". Frame of reference is the street's own cross-section, not the camera: \"left\" is the inbound side and \"right\" the outbound side (right-hand-drive convention; swap for left-hand-drive countries). segments[0] sits at the first edge; getGeoContext reports the compass bearing of each edge.",
                "enum": [
                  "left",
                  "right"
                ]
              },
              "generated": {
                "type": "object",
                "description": "Optional generated content — omit to receive the type preset. Two different systems: `clones` places 3D models (vehicles, cyclists, trees, lamps, furniture — any listMixins id with generator \"clones\"); `stencil` paints flat road markings (arrows, sharrows, words like BUS ONLY — only ids with generator \"stencil\"). Never put a vehicle in `stencil` or a marking in `clones`.",
                "properties": {
                  "clones": {
                    "type": "array",
                    "description": "Clones configuration for repeated 3D models",
                    "items": {
                      "type": "object",
                      "properties": {
                        "mode": {
                          "type": "string",
                          "description": "Clone mode (\"random\", \"fixed\", \"single\")"
                        },
                        "modelsArray": {
                          "type": "string",
                          "description": "Comma-separated 3D model ids from listMixins (generator \"clones\"), e.g. \"sedan-rig, box-truck-rig\" or \"bus\". Unknown ids are rejected."
                        },
                        "spacing": {
                          "type": "number",
                          "description": "Distance between models in meters"
                        },
                        "count": {
                          "type": "number",
                          "description": "Number of models (for random mode)"
                        },
                        "facing": {
                          "type": "number",
                          "description": "Rotation in degrees"
                        },
                        "randomFacing": {
                          "type": "boolean",
                          "description": "Random rotation"
                        },
                        "cycleOffset": {
                          "type": "number",
                          "description": "Offset in the repeating pattern (0-1)"
                        }
                      },
                      "required": [
                        "mode",
                        "modelsArray",
                        "spacing"
                      ]
                    }
                  },
                  "stencil": {
                    "type": "array",
                    "description": "Stencil configuration for road markings",
                    "items": {
                      "type": "object",
                      "properties": {
                        "modelsArray": {
                          "type": "string",
                          "description": "Comma-separated painted-marking ids (generator \"stencil\"), e.g. \"bike-arrow\", \"sharrow\", \"word-bus, word-only\". Unknown ids are rejected — use listMixins."
                        },
                        "spacing": {
                          "type": "number",
                          "description": "Distance between stencils"
                        },
                        "padding": {
                          "type": "number",
                          "description": "Edge padding"
                        },
                        "cycleOffset": {
                          "type": "number",
                          "description": "Pattern offset (0-1)"
                        },
                        "direction": {
                          "type": "string",
                          "description": "Stencil orientation"
                        },
                        "stencilHeight": {
                          "type": "number",
                          "description": "Height of stencil"
                        }
                      },
                      "required": [
                        "modelsArray",
                        "spacing"
                      ]
                    }
                  },
                  "pedestrians": {
                    "type": "array",
                    "description": "Pedestrian configuration",
                    "items": {
                      "type": "object",
                      "properties": {
                        "density": {
                          "type": "string",
                          "description": "Pedestrian density (\"normal\", \"dense\")"
                        }
                      },
                      "required": [
                        "density"
                      ]
                    }
                  },
                  "striping": {
                    "type": "array",
                    "description": "Striping configuration for lane markings",
                    "items": {
                      "type": "object",
                      "properties": {
                        "striping": {
                          "type": "string",
                          "description": "Stripe pattern type"
                        },
                        "side": {
                          "type": "string",
                          "description": "Side of segment (\"left\", \"right\")"
                        }
                      },
                      "required": [
                        "striping"
                      ]
                    }
                  }
                }
              }
            },
            "required": []
          }
        },
        "required": [
          "entityId",
          "operation"
        ]
      }
    }
    takeSnapshotAction

    Render a snapshot of the scene and return it as a JPEG image (max 1280 px wide) plus `metadata.camera` (tilt, isTopDown, isNorthUp, screenUpBearingDeg, lat/lon). To VERIFY placement or alignment use type "plan": top-down, north-up, whole scene — the only view with absolute orientation. One plan snapshot beats several angled ones; do not take multiple perspective shots to check position. In a geospatial scene "plan" is the default when type is omitted.

    View tool JSON
    {
      "name": "takeSnapshot",
      "kind": "act",
      "impl": "imperative",
      "description": "Render a snapshot of the scene and return it as a JPEG image (max 1280 px wide) plus `metadata.camera` (tilt, isTopDown, isNorthUp, screenUpBearingDeg, lat/lon). To VERIFY placement or alignment use type \"plan\": top-down, north-up, whole scene — the only view with absolute orientation. One plan snapshot beats several angled ones; do not take multiple perspective shots to check position. In a geospatial scene \"plan\" is the default when type is omitted.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "caption": {
            "type": "string",
            "description": "Optional caption to display with the snapshot"
          },
          "focusEntityId": {
            "type": "string",
            "description": "Optional entity ID to focus on before taking the snapshot"
          },
          "type": {
            "type": "string",
            "description": "View to render. \"plan\": top-down, north-up, whole scene — use this to judge orientation and alignment (default in geospatial scenes). \"focus\": current view, or framed on focusEntityId (default otherwise). \"birdseye\", \"straightOn\", \"closeup\": presentation shots of the first managed street — not orientation references; use them only when the user asks for a picture, not to verify.",
            "enum": [
              "focus",
              "plan",
              "birdseye",
              "straightOn",
              "closeup"
            ]
          },
          "zoomOut": {
            "type": "number",
            "description": "Plan view only: altitude multiplier applied after the top-down fit. 1 = street fills the frame; 2 (default in geospatial scenes) shows about twice the ground extent so the real roads around the street are visible; use 3-4 for a wider context check. The result reports `metadata.groundExtent` (visible metres across the viewport)."
          }
        },
        "required": []
      }
    }
    setLatLonAction

    Set the latitude and longitude for the scene, which triggers elevation lookup and activates the Google 3D Tiles map layer. Signed-in users can set any location; signed-out sessions are limited to locations within California (demo).

    View tool JSON
    {
      "name": "setLatLon",
      "kind": "act",
      "impl": "imperative",
      "description": "Set the latitude and longitude for the scene, which triggers elevation lookup and activates the Google 3D Tiles map layer. Signed-in users can set any location; signed-out sessions are limited to locations within California (demo).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "latitude": {
            "type": "number",
            "description": "Latitude in decimal degrees (e.g., 37.7637072)"
          },
          "longitude": {
            "type": "number",
            "description": "Longitude in decimal degrees (e.g., -122.4151768)"
          }
        },
        "required": [
          "latitude",
          "longitude"
        ]
      }
    }
    getSceneAnswer

    Return the full 3DStreet scene as Format-1 JSON (the same data the Save button writes), plus the currently selected entity id and scene id.

    View tool JSON
    {
      "name": "getScene",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the full 3DStreet scene as Format-1 JSON (the same data the Save button writes), plus the currently selected entity id and scene id.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    }
    getEntityAnswer

    Return one entity serialized as Format-1 JSON.

    View tool JSON
    {
      "name": "getEntity",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return one entity serialized as Format-1 JSON.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "The DOM id of the entity to read"
          }
        },
        "required": [
          "entityId"
        ]
      }
    }
    getSelectedEntityAnswer

    Return the entity the user has selected in the scene graph (or null).

    View tool JSON
    {
      "name": "getSelectedEntity",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the entity the user has selected in the scene graph (or null).",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    }
    selectEntityAction

    Programmatically select an entity (mirrors clicking it in the scene graph). Pass an empty entityId to clear selection.

    View tool JSON
    {
      "name": "selectEntity",
      "kind": "act",
      "impl": "imperative",
      "description": "Programmatically select an entity (mirrors clicking it in the scene graph). Pass an empty entityId to clear selection.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "The DOM id to select; pass empty string to clear selection."
          }
        },
        "required": [
          "entityId"
        ]
      }
    }
    listMixinsAnswer

    List available A-Frame mixins (model assets) grouped by category. Optional category arg filters to one category.

    View tool JSON
    {
      "name": "listMixins",
      "kind": "answer",
      "impl": "imperative",
      "description": "List available A-Frame mixins (model assets) grouped by category. Optional category arg filters to one category.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "category": {
            "type": "string",
            "description": "Optional category label to filter by"
          }
        },
        "required": []
      }
    }
    listSegmentPresetsAnswer

    List the per-type segment presets (surface, color, elevation, default direction, and the generated stencils/clones/pedestrians) that managedStreetCreate and managedStreetUpdate apply when a segment omits those fields — identical to picking the type in the editor sidebar. Read this before composing a cross-section so you only override what you need.

    View tool JSON
    {
      "name": "listSegmentPresets",
      "kind": "answer",
      "impl": "imperative",
      "description": "List the per-type segment presets (surface, color, elevation, default direction, and the generated stencils/clones/pedestrians) that managedStreetCreate and managedStreetUpdate apply when a segment omits those fields — identical to picking the type in the editor sidebar. Read this before composing a cross-section so you only override what you need.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    }
    getSessionInfoAnswer

    Return the running build version, signed-in user, current scene id/url/title, whether edits are being persisted (`saved`: cloud scene exists and the user is its author, so autosave is on — otherwise call saveScene), and viewport size.

    View tool JSON
    {
      "name": "getSessionInfo",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the running build version, signed-in user, current scene id/url/title, whether edits are being persisted (`saved`: cloud scene exists and the user is its author, so autosave is on — otherwise call saveScene), and viewport size.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    }
    getManagedStreetAnswer

    Return one managed-street entity as Format-2 segment-list JSON (reverse of the parser, reads live DOM so it includes per-segment edits).

    View tool JSON
    {
      "name": "getManagedStreet",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return one managed-street entity as Format-2 segment-list JSON (reverse of the parser, reads live DOM so it includes per-segment edits).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "The DOM id of a managed-street entity"
          }
        },
        "required": [
          "entityId"
        ]
      }
    }
    undoAction

    Step the editor history back by one command.

    View tool JSON
    {
      "name": "undo",
      "kind": "act",
      "impl": "imperative",
      "description": "Step the editor history back by one command.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    }
    redoAction

    Step the editor history forward by one command.

    View tool JSON
    {
      "name": "redo",
      "kind": "act",
      "impl": "imperative",
      "description": "Step the editor history forward by one command.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    }
    getGeoContextAnswer

    Return the exact relationship between scene coordinates and geographic coordinates: the lat/lon at the scene origin, the compass bearing of the scene axes, the camera pose (tilt, north-up state, lat/lon), and optionally one entity converted to lat/lon + compass heading (for a managed street: centerline bearing and both endpoint coordinates), and/or a lat/lon converted to a scene world position. Conversions use the live Google 3D Tiles WGS84 frame, so they match where the map renders. Errors with a reason when the geo layer is off or still loading — call setLatLon or retry.

    View tool JSON
    {
      "name": "getGeoContext",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the exact relationship between scene coordinates and geographic coordinates: the lat/lon at the scene origin, the compass bearing of the scene axes, the camera pose (tilt, north-up state, lat/lon), and optionally one entity converted to lat/lon + compass heading (for a managed street: centerline bearing and both endpoint coordinates), and/or a lat/lon converted to a scene world position. Conversions use the live Google 3D Tiles WGS84 frame, so they match where the map renders. Errors with a reason when the geo layer is off or still loading — call setLatLon or retry.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "Optional entity to describe geographically (position → lat/lon, heading → compass bearing; managed streets also get endpoint coordinates)."
          },
          "latitude": {
            "type": "number",
            "description": "Optional latitude to convert to a scene world position (pair with longitude)."
          },
          "longitude": {
            "type": "number",
            "description": "Optional longitude to convert to a scene world position (pair with latitude)."
          }
        },
        "required": []
      }
    }
    orientPlanViewAction

    Move the editor camera to a top-down, north-up plan view using the same compass action a user clicks (perspective camera, framing the whole scene), optionally pulled back by `zoomOut`. Returns the resulting camera state (tilt, needle angle, isTopDown, isNorthUp, lat/lon, groundExtent in metres). Use before takeSnapshot when judging alignment or orientation; focusCamera reframes around one entity and is NOT a reliable orientation reference. takeSnapshot type "plan" does this for you.

    View tool JSON
    {
      "name": "orientPlanView",
      "kind": "act",
      "impl": "imperative",
      "description": "Move the editor camera to a top-down, north-up plan view using the same compass action a user clicks (perspective camera, framing the whole scene), optionally pulled back by `zoomOut`. Returns the resulting camera state (tilt, needle angle, isTopDown, isNorthUp, lat/lon, groundExtent in metres). Use before takeSnapshot when judging alignment or orientation; focusCamera reframes around one entity and is NOT a reliable orientation reference. takeSnapshot type \"plan\" does this for you.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "zoomOut": {
            "type": "number",
            "description": "Altitude multiplier after the fit: 1 = scene fills the frame, 2 = twice the ground extent (see surrounding real roads), 3-4 = wide context."
          }
        },
        "required": []
      }
    }
    focusCameraAction

    Frame an entity in the viewport (same effect as double-clicking it in the scene graph). This reframes and rotates the view around that entity, so the result is NOT a north-up or alignment reference — use orientPlanView + takeSnapshot for that.

    View tool JSON
    {
      "name": "focusCamera",
      "kind": "act",
      "impl": "imperative",
      "description": "Frame an entity in the viewport (same effect as double-clicking it in the scene graph). This reframes and rotates the view around that entity, so the result is NOT a north-up or alignment reference — use orientPlanView + takeSnapshot for that.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entityId": {
            "type": "string",
            "description": "The DOM id to focus on"
          }
        },
        "required": [
          "entityId"
        ]
      }
    }
    saveSceneAction

    Persist the current scene to the signed-in user's cloud account. Edits are NOT saved until this is called once; afterwards autosave persists every further edit in this tab. Returns sceneId and sceneUrl — always give the user the sceneUrl (or remember the sceneId) so the work can be reopened in a later session with loadScene. Signed out: opens the sign-in modal and errors; ask the user to sign in, then retry. If the open scene belongs to someone else, saves a copy.

    View tool JSON
    {
      "name": "saveScene",
      "kind": "act",
      "impl": "imperative",
      "description": "Persist the current scene to the signed-in user's cloud account. Edits are NOT saved until this is called once; afterwards autosave persists every further edit in this tab. Returns sceneId and sceneUrl — always give the user the sceneUrl (or remember the sceneId) so the work can be reopened in a later session with loadScene. Signed out: opens the sign-in modal and errors; ask the user to sign in, then retry. If the open scene belongs to someone else, saves a copy.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Optional scene title to set before saving (e.g. \"Geary Blvd BRT\")."
          }
        },
        "required": []
      }
    }
    loadSceneAction

    Replace the current scene with a saved cloud scene by id — the way to resume earlier work (e.g. when the user says "resume my scene" and you remember its sceneId, or from a sceneUrl). Unsaved edits in the current scene are discarded, so saveScene first if they matter.

    View tool JSON
    {
      "name": "loadScene",
      "kind": "act",
      "impl": "imperative",
      "description": "Replace the current scene with a saved cloud scene by id — the way to resume earlier work (e.g. when the user says \"resume my scene\" and you remember its sceneId, or from a sceneUrl). Unsaved edits in the current scene are discarded, so saveScene first if they matter.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "sceneId": {
            "type": "string",
            "description": "Scene UUID, or a 3DStreet URL containing /scenes/<uuid>."
          }
        },
        "required": [
          "sceneId"
        ]
      }
    }