Geometry (Node-first): ray/surface intercepts (raw.sincpt)
This recipe is Node.js-first and uses the native addon backend (backend: "node").
We’ll compute a surface intercept point on the Moon by tracing a ray from Earth toward the Moon.
Kernels required (and why)
- LSK (
*.tls): required forkit.utcToEt(). - SPK (
*.bsp): required to get Earth→Moon state/position. - PCK (
*.tpc): required forIAU_MOON+ Moon radii (ellipsoid shape).
Load kernels from filesystem paths
In Node, kernel sources are just filesystem paths (strings):
ts
import path from 'node:path'
import { spiceClients } from '@rybosome/tspice'
const kernelsDir = path.resolve('kernels')
const { spice, dispose } = await spiceClients.toAsync({ backend: 'node' })
try {
await spice.kit.loadKernel(path.join(kernelsDir, 'naif0012.tls'))
await spice.kit.loadKernel(path.join(kernelsDir, 'pck00011.tpc'))
await spice.kit.loadKernel(path.join(kernelsDir, 'de432s.bsp'))
// …geometry query…
} finally {
await dispose()
}Example: intercept the Moon along an Earth→Moon ray
ts
const toDegrees = (rad: number): number => (rad * 180) / Math.PI
const et = await spice.kit.utcToEt('2024-01-01T00:00:00Z')
const method = 'ELLIPSOID'
const target = 'MOON'
const fixref = 'IAU_MOON'
const abcorr = 'NONE'
const observer = 'EARTH'
// Direction reference frame for the ray.
const dref = 'J2000'
// Aim the ray at the Moon by using the Earth→Moon position vector.
const { pos: earthToMoon } = await spice.raw.spkpos(target, et, dref, abcorr, observer)
const out = await spice.raw.sincpt(
method,
target,
et,
fixref,
abcorr,
observer,
dref,
earthToMoon,
)
if (!out.found) {
throw new Error('Ray missed the target (no intercept found)')
}
// `spoint` is the intercept point in the target body-fixed frame (`fixref`).
const { spoint, trgepc, srfvec } = out
// Convert rectangular coordinates -> planetocentric lon/lat (radians).
const { radius, lon, lat } = await spice.raw.reclat(spoint)
console.log({
trgepc,
spointKm: spoint,
observerToSurfaceKm: srfvec,
lonDeg: toDegrees(lon),
latDeg: toDegrees(lat),
radiusKm: radius,
})Interpreting the result
found: falsemeans the ray does not hit the target body.spointis the intercept point in the target body-fixed frame you passed asfixref. In this example that’sIAU_MOON.srfvecis the vector from the observer to the surface point (in thefixrefframe).trgepcis the “target epoch” (it can differ from your inputetwhen you use aberration corrections other than"NONE").