## Technical details

### External dependencies

The dyna3 program depends on some externally-maintained JavaScript libraries/modules. The package uses npm to track these external dependencies. A module externals.js is automatically generated from the package.json and package_lock.json files created by npm to load the necessary modules at runtime.

The generation is performed by pkglock_to_externals.litcoffee, which also records all of the needed importable files within the library, as there's no way to generate that from the module name or the information in package-lock.json.

Specific packages/implementation approaches for components of dyna3 include the following items. All packages are obtained from npm unless otherwise noted.

- for conversion of markdown to HTML: pandoc
- For a test harness for the package: Ava
  - When a point is reached at which there is a need to test in-browser behavior, ava can call Puppeteer as per https://github.com/avajs/ava/blob/master/docs/recipes/puppeteer.md
- For WebGL rendering of the 3D view of the geometry: three

```javascript

    importable =
        three:
            three: 'build/three.module.js',
            TrackballControls: 'examples/jsm/controls/TrackballControls.js'

```
And here is the current complete list of external libraries on which operation of dyna3 depends:
```javascript

    if process.argv.length < 3
        header =
        """
        /* External module loader for dyna3
         * Generated automatically from package-lock.json by
         * helpers/pkglock_to_externals.litcoffee
         */

        """
        process.stdout.write header
    fs = require 'fs'
    pkdata = JSON.parse fs.readFileSync 'package.json'
    pldata = JSON.parse fs.readFileSync 'package-lock.json'
    for dep in Object.keys pkdata.dependencies
        if process.argv.length > 2
            process.stdout.write "- #{dep}\n"
        else
            exports = (
                "export var #{mod};" for mod in Object.keys importable[dep]
            ).join "\n"

            mainload = (
                "#{mod} = await import('https://cdn.jsdelivr.net/npm/#{dep}@#{pldata.dependencies[dep].version}/#{importable[dep][mod]}');" for mod in Object.keys importable[dep]
            ).join "\n        "

            fallbackload = (
                "#{mod} = await import('./node_modules/#{dep}/#{importable[dep][mod]}');" for mod in Object.keys importable[dep]
            ).join "\n            "

            block =
            """
            #{exports}
            export var #{dep}Loaded = new Promise(async function(resolve, reject) {
                var success = false;
                try {
                    #{mainload}
                    console.log('CDN import of #{dep} module OK');
                    success = true;
                } catch(err) {
                    console.log('CDN import of #{dep} failed: ' + JSON.stringify(err));
                    try {
                        #{fallbackload}
                        success = true;
                    } catch(err) {
                    }
                    console.log('Used local fallback for #{dep} module');
                }
                if (success) { resolve(); } else { reject(); }
            });
            """
            process.stdout.write block

```
