SkyScript Scenery API
The Scenery API provides access to X-Plane's scenery system including object loading, terrain probing, and magnetic variation.
Overview
// Access through the XPlane global
XPlane.scenery.loadObject(path);
XPlane.scenery.probeTerrain(probeId, x, y, z);
XPlane.scenery.getMagneticVariation(lat, lon);Object Loading
loadObject
Load an OBJ file from the X-System folder.
const objPath = XPlane.scenery.loadObject(path: string): string | null;Parameters:
path- Path to the .obj file relative to X-System folder
Returns: The object path as handle, or null if loading failed
Example:
// Load a pushback tug
const tug = XPlane.scenery.loadObject(
"Resources/default scenery/sim objects/apt_vehicles/pushback/Goldhofer_AST1_Tow.obj"
);
if (tug) {
console.log("Loaded pushback tug");
}unloadObject
Unload a previously loaded object.
const success = XPlane.scenery.unloadObject(path: string): boolean;Parameters:
path- The object path/handle returned fromloadObject
Returns: true if successful
Example:
// Clean up when done
XPlane.scenery.unloadObject(tug);Terrain Probing
Terrain probing allows you to query the height and properties of terrain at any location.
createProbe
Create a terrain probe.
const probeId = XPlane.scenery.createProbe(probeType?: number): number | null;Parameters:
probeType- (Optional) Type of probe. Default is0(Y probe - finds terrain height)
Returns: Probe handle ID, or null if failed
Example:
const probeId = XPlane.scenery.createProbe();destroyProbe
Destroy a terrain probe when no longer needed.
const success = XPlane.scenery.destroyProbe(probeId: number): boolean;Parameters:
probeId- The probe handle ID
Returns: true if successful
probeTerrain
Probe terrain at an XYZ location in local OpenGL coordinates.
const result = XPlane.scenery.probeTerrain(
probeId: number,
x: number,
y: number,
z: number
): TerrainProbeResult;Parameters:
probeId- The probe handle IDx- X coordinate (local OpenGL)y- Y coordinate (local OpenGL)z- Z coordinate (local OpenGL)
Returns: A TerrainProbeResult object:
interface TerrainProbeResult {
hit: boolean; // Whether the probe hit terrain
result?: number; // Probe result code (only if hit is false)
x?: number; // X coordinate of hit
y?: number; // Y coordinate of hit (terrain height)
z?: number; // Z coordinate of hit
normalX?: number; // X component of terrain normal
normalY?: number; // Y component of terrain normal
normalZ?: number; // Z component of terrain normal
velocityX?: number; // X velocity (for moving platforms)
velocityY?: number; // Y velocity
velocityZ?: number; // Z velocity
isWet?: boolean; // Whether the terrain is water
}Example:
// Get aircraft position
const x = XPlane.dataref.getDouble("sim/flightmodel/position/local_x");
const y = XPlane.dataref.getDouble("sim/flightmodel/position/local_y");
const z = XPlane.dataref.getDouble("sim/flightmodel/position/local_z");
// Probe terrain below aircraft
const result = XPlane.scenery.probeTerrain(probeId, x, y, z);
if (result.hit) {
const terrainHeight = result.y;
const agl = y - terrainHeight;
console.log(`Height AGL: ${agl.toFixed(1)} meters`);
if (result.isWet) {
console.log("Over water");
}
}Magnetic Variation
getMagneticVariation
Get magnetic variation at a geographic location.
const variation = XPlane.scenery.getMagneticVariation(
latitude: number,
longitude: number
): number;Parameters:
latitude- Latitude in degreeslongitude- Longitude in degrees
Returns: Magnetic variation in degrees (positive = east)
Example:
// Get magnetic variation at Seattle
const variation = XPlane.scenery.getMagneticVariation(47.4502, -122.3088);
console.log(`Magnetic variation: ${variation.toFixed(1)}°`);degTrueToMagnetic
Convert true heading to magnetic heading at current aircraft location.
const magHeading = XPlane.scenery.degTrueToMagnetic(headingTrue: number): number;Parameters:
headingTrue- True heading in degrees
Returns: Magnetic heading in degrees
Example:
// Convert runway true heading to magnetic
const trueHeading = 340;
const magHeading = XPlane.scenery.degTrueToMagnetic(trueHeading);
console.log(`Runway ${Math.round(magHeading / 10)}`);degMagneticToTrue
Convert magnetic heading to true heading at current aircraft location.
const trueHeading = XPlane.scenery.degMagneticToTrue(headingMagnetic: number): number;Parameters:
headingMagnetic- Magnetic heading in degrees
Returns: True heading in degrees
Complete Example
// Terrain-aware object placement
async function placeObjectOnTerrain(objPath: string, lat: number, lon: number, heading: number) {
// Load the object
const obj = XPlane.scenery.loadObject(objPath);
if (!obj) {
console.error("Failed to load object");
return null;
}
// Convert world coords to local
const local = XPlane.graphics.worldToLocal(lat, lon, 0);
// Create a probe and find terrain height
const probeId = XPlane.scenery.createProbe();
const terrain = XPlane.scenery.probeTerrain(probeId, local.x, local.y, local.z);
XPlane.scenery.destroyProbe(probeId);
if (!terrain.hit) {
console.error("Could not probe terrain");
return null;
}
// Create instance at terrain level
const instanceId = XPlane.instance.create(obj);
if (!instanceId) {
console.error("Failed to create instance");
return null;
}
// Position on terrain with correct heading
XPlane.instance.setPosition(instanceId, {
x: terrain.x!,
y: terrain.y!,
z: terrain.z!,
heading: heading,
pitch: 0,
roll: 0
});
return { obj, instanceId };
}
// Usage
const vehicle = await placeObjectOnTerrain(
"Resources/default scenery/sim objects/apt_vehicles/pushback/Goldhofer_AST1_Tow.obj",
47.4502,
-122.3088,
90
);
// Clean up later
if (vehicle) {
XPlane.instance.destroy(vehicle.instanceId);
XPlane.scenery.unloadObject(vehicle.obj);
}See Also
- Instance API - Creating and managing object instances
- Graphics API - Coordinate conversions
- DataRef API - Reading simulator data