TimeCraftJS is a time conversion library that uses NAIF's CSPICE. It exposes functions to execute operations to convert SCET, ET, SCT, furnish Kernels, among others, on the client side. This avoid unnecessary trips to the backend and allows for important time operations to happen if network connectivity is not immediately available. Multiple variants of the built CSPICE library are provided, including a limited, low-memory "lite" version with lesser functionality which is loaded by default. See Constants section and init function description for more information on the options.
Some basic kernels are provided in this repo for performing time conversions. More kernels for other missions can be found here.
npm install timecraftjs
The compiled emscripten blob includes require( 'fs' )
which can cause Webpack to fail to compile for the web. In this case add the following options to the root of your Webpack config:
node: {
fs: "empty";
}
import { Spice } from "timecraftjs";
const spiceInstance = await new Spice().init();
// Load the kernels
const kernelBuffers = await Promise.all([
fetch("../kernels/lsk/naif0012.tls").then((res) => res.buffer()),
fetch("../kernels/spk/de425s.bsp").then((res) => res.buffer()),
fetch("../kernels/pck/pck00008.tpc").then((res) => res.buffer()),
]);
// Load the kernels into Spice
for (let i = 0; i < kernelBuffers.length; i++) {
spiceInstance.loadKernel(kernelBuffers[i]);
}
// Time conversion!
const utc = new Date().toISOString().slice(0, -1);
const et = spiceInstance.utc2et(utc);
const lst = spiceInstance.et2lst(et, 499, 0, "planetocentric");
import { Spice, parseMetakernel } from "timecraftjs";
const spiceInstance = await new Spice().init();
// load the kernel contents
const metaKernel = await fetch(
"../kernels/extras/mk/msl_chronos_v07.tm"
).then((res) => res.text());
// parse the kernel
const kernelPaths = parseMetakernel(metaKernel).paths;
// load the kernels in the meta kernel
const kernelPromises = kernelPaths.map((p) => {
return fetch(p)
.then((res) => res.buffer())
.then((buffer) => spiceInstance.loadKernel(buffer));
});
await Promise.all(kernelPromises);
// ready for time conversion!
spiceInstance.chronos("617885388.6646054", "-from et -to utc -fromtype SECONDS");
- Clone the Repository
git clone https://github.com/NASA-AMMOS/timecraftjs.git
- Run the following on the base directory:
npm install
npm start
This will start a static server so you can visit the example page at localhost:9080/example/
.
TimecraftJS is a time conversion library that uses NAIF's CSPICE. In order to accomplish this, we automatically converted the C source code into Javascript via Emscripten. In order for them to work in a much more user friendly and Javascript-like way, we have created wrapper functions that interact with the resulting simulated C program, allocating and deallocating memory as necessary. This project only includes wrappers for the functions relevant to time conversion and some light time calculations. This project is an offshoot of spice.js.
A great deal below deals with the loading and furnishing of kernels. If you do not wish to do any time conversions involving specific spacecraft or planets, the default included kernels are sufficient and you may ignore these sections. The default kernels are enough to refer to most NAIF ID's, a planetary constants kernel, and a leap seconds kernel. See example-timecraftjs.html for a simple demo of TimeCraftJS working.
This section lists the files included in this package and describes what each of them does. This section is mainly for people who wish to modify this package, if you simply wish to use it you can likely skip this section.
These files contain the emscripten-converted CSPICE source code. It is extremely large and should not be modified. Both a "full" and "lite" version of converted CSPICE is provided. See the Constants section for more information on the variants.
This file contains the wrapper class that allows access to the functionality in cspice.js. The version of spice.js here is focused on time conversions, but the rest of the CSPICE functionality could be exposed if needed.
Constants for use in the Spice.init function to intialize the library to use either a full or lite version of the SPICE library.
Use this constant to load and use the full asm.js version of the SPICE library with full functionality. Run time memory requirement is around 100 MB.
Use this constant to load and use an asm.js version of an unofficial "lite" version of the SPICE library with some missing functonality to improve memory requirements. Specifically all ek*
functions have been removed and various internal constants have been lowered to reduce memory use. Not all NAIF kernels can be guaranteed to function when using this reduced memory of the package. If an error occurs due to overrunning memory use the "full" version, instead. Run time memory requirement is around 20 MB.
Class used to instantiate an instance of Spice. Multiple instances can be created to load different kernels if desired. init must be called before use.
Note that due to the memory requirements of CSpice each instance of this class will take around 100MB of memory.
ready : Boolean
Whether the class has been fully initialized after init has been called.
whenReady : Promise<this>
Resolves when the class has been fully initialized after init has been called.
onStdOut : ( log : String ) => void
Callback that gets fired whenever CSpice logs to stdout. Defaults to log to console.
onStdErr : ( log : String ) => void
Callback that gets fired whenever CSpice logs to stderr. Defaults to log error to console.
module : Object = null
This is the raw Emscripten compiled module that is used to call CSpice functions and interact with the virtual file system. There is typically no need to use this object but unexposed CSpice functions can be called here using ccall
.
Module
and FS
are created by Emscripten to interact directly with the ported C code and with the simulated C file system. Avoid using them unless you have read the Interacting With Code and preamble.js sections of the Emscripten documentation.
module
is null until init has fully resolved.
init( type : ( ASM_SPICE_LITE | ASM_SPICE_FULL ) = ASM_SPICE_LITE ) : Promise<this>
Loads and initializes the CSpice module. The class is ready to use once the promise has resolved.
The "type" parameter can be used to dictate which version of the compiled CSPICE module to use. See the Constants section for available options and more information. Defaults to using the "lite" version of the module.
loadKernel( buffer : ArrayBuffer | Uint8Array, key : String = null ) : void
Load the provided buffer into Spice as a kernel. The provided key can be used to unload the kernel using unloadKernel. Throws an error if the key has already been used. Details of kernel management can be found in the Kernel Management section of the SPICE docs.
unloadKernel( key : String ) : void
Unload the kernel that was loaded with the given key. Throws an error if a kernel has not been loaded with the given key.
chronos( inptim : String, cmdlin : String ) : String
Wrapper for the CSpice command line utility that calls the cronos_
function internally. inptim
is the input time to convert while cmdlin
is the list of command line arguments as a string. See the chronos docs for more information.
Most of the functions made available in this library are functions from CSPICE called in a more Javascript-like way. Please see differences between cspice and spice.js for specifics.
While the ported C code technically contains all CSPICE functionality, the following functions have been exposed in this class. The CSPICE documentation for each of these functions is correct, but below you can see their more Javascript-like call format supported here. All documented CSpice function inputs are passed into the Javascript equivelants below while all outputs are returned as a dictionary indexed by parameter name or as a single value if there is only a single output.
b1900()
b1950()
bodc2n( code )
bodc2s( code )
boddef( name, code )
bodfnd( body, item )
bodn2c( name )
bods2c( name )
bodvcd( bodyid, item, maxn )
bodvrd( body, item, maxn )
convrt( x, in_var, out )
deltet( epoch, eptype )
erract( op, action )
errprt( op, list )
et2lst( et, body, lon, type )
et2utc( et, format, prec )
etcal( et )
failed()
furnsh( kernelPaths )
getmsg( options )
j1900()
j1950()
j2000()
j2100()
jyear()
ltime( etobs, obs, dir, targ )
reset()
scdecd( sc, sclkdp )
sce2c( sc, et )
sce2s( sc, et )
sce2t( sc, et )
scencd( sc, sclkch )
scfmt( sc, ticks )
scpart( sc )
scs2e( sc, sclkch )
sct2e( sc, sclkdp )
sctiks( sc, clkstr )
spd()
spkpos( targ, et, ref, abcorr, obs )
str2et( str )
timdef( action, item, value )
timout( et, pictur )
tparse( string )
tpictr( sample )
tsetyr( year )
tyear()
unitim( epoch, insys, outsys )
unload( file )
utc2et( utcstr )
isMetakernel( contents : String | ArrayBuffer | Uint8Array ) : Boolean
Takes the contents of a kernel file and returns true
if it is a metakernal and false
otherwise. This function looks for the KERNELS_TO_LOAD
token in the file.
parseMetakernel( contents : String | ArrayBuffer | Uint8Array ) : { fields: Object, paths: Array<String> }
Parses the contents of a metakernel .tm
file and returns all the key value pairs in the file as fields
and all preprocessed referenced metakernal paths as paths
.
In order to load an read kernels the data must be loaded into the virtual Emscripten file system as a binary buffer.
Files must be downloaded asynchronously as array buffers before being loaded into the app.
import { Spice } from "timecraftjs";
const spiceInstance = await new Spice().init();
const kernelBuffer = await fetch("../path/to/kernel").then((res) => res.buffer);
spiceInstance.loadKernel(buffer);
In node files can be loaded from the filesystem directly.
import fs from "fs";
import { Spice } from "timecraftjs";
const spiceInstance = await new Spice().init();
const kernelBuffer = fs.readFileSync("../path/to/kernel");
spiceInstance.loadKernel(buffer);
The files in src/cspice/
are the massive Javascript files resulting from the automatic porting via Emscripten. As such, if CSPICE updates, these files will need to be recompiled. In order to recompile any of the JS CSPICE files, follow these steps:
- Download relevant toolkit from the NAIF website.
- Download emsdk to download and manage "emscripten" versions.
- Install the latest version of emscripten and source the emsdk environment variables from
emsdk_env.sh
.
The current version was created from the Mac/OSX 64 Bit Toolkit on April 12, 2021 with emscripten version 2.0.17.
- Unzip the CSPICE source folder and put the contents into the
generation/cspice-full
folder. - Ensure the
LITE_BUILD
variable is set toFalse
ingeneration/generate-cspice.sh
. - Run
generation/generate-cspice.sh
to generate the js library file in the folder. - Move the newly generated
asm_full.js
file into thesrc/cspice
folder.
INTERNAL ONLY
The modified lite version of the CSPICE used was dervied from the latest version of CSPICE on April 27, 2021 with emscripten version 2.0.17. The CSPICE lite code only provides modified src/cspice
functions so necessary chronos functionality is copied from the latest public version.
- Unzip the latest CSPICE source folder (see above) and put the contents into the
generation/cspice-full
folder. - Unzip the CSPICE lite source folder and put the contents into the
generation/cspice-lite
folder. Modified CSPICE lite source available here (internal only). - Ensure the
LITE_BUILD
variable is set toTrue
ingeneration/generate-cspice.sh
. - Run
generation/generate-cspice.sh
to generate the js library file in the folder. - Move the newly generated
asm_lite.js
file into thesrc/cspice
folder.
Copyright 2020, by the California Institute of Technology. ALL RIGHTS RESERVED. United States Government Sponsorship acknowledged. Any commercial use must be negotiated with the Office of Technology Transfer at the California Institute of Technology. This software may be subject to U.S. export control laws. By accepting this software, the user agrees to comply with all applicable U.S. export laws and regulations. User has the responsibility to obtain export licenses, or other export authority as may be required before exporting such information to foreign countries or providing access to foreign persons.