@metaverse-systems/the-seed
v1.2.1
Published
The Seed
Readme
@metaverse-systems/the-seed
A CLI tool and TypeScript library for scaffolding, building, and cross-compiling C++ ECS projects built on the libecs-cpp framework. It provides project templates, dependency management, native and Windows cross-compilation workflows, and a programmatic API for integration into custom tooling.
Architecture
The project consists of four repositories with a linear dependency chain:
libecs-cpp --> libthe-seed --> the-seed --> the-seed-vscodelibecs-cpp -- A C++20 Entity Component System framework providing Manager, Container, Entity, Component, System, Timing, and Uuid classes. Built with GNU Autotools and distributed via pkg-config as ecs-cpp.
GitHub: https://github.com/metaverse-systems/libecs-cpp
libthe-seed -- A C++20 engine runtime that depends on libecs-cpp. Provides LibraryLoader, ComponentLoader, SystemLoader, JSONLoader, ResourcePak, NameParser, and DependencyLister. Built with GNU Autotools and distributed via pkg-config as the-seed.
GitHub: https://github.com/metaverse-systems/libthe-seed
the-seed -- A TypeScript CLI tool and npm package (@metaverse-systems/the-seed) with a C++ N-API native addon (node-gyp). Wraps DependencyLister for shared library dependency analysis. Provides 7 CLI commands for scaffolding, building, and packaging.
GitHub: https://github.com/metaverse-systems/the-seed
the-seed-vscode -- A TypeScript VS Code extension that depends on @metaverse-systems/the-seed. Provides the "The Seed: Create ResourcePak" command for creating resource paks from within the editor.
GitHub: https://github.com/metaverse-systems/the-seed-vscode
Prerequisites
Required
- Node.js v16+ and npm
sudo apt install build-essential libtool pkg-config autoconf automake curl gitOptional: Windows Cross-Compilation
These packages are only needed if you intend to cross-compile projects for Windows:
sudo apt install mingw-w64-x86-64-dev g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 wine wine64Installation
npm install -g @metaverse-systems/the-seedVerify the installation:
the-seed helpExpected output:
Usage: the-seed <command>
Commands:
config
scopes
template
build
dependencies
package
resource-pakQuick Start
Step 1: Configure the installation prefix
the-seed config edit? Installation prefix? ~/the-seedThis creates ~/the-seed/config.json with your chosen prefix.
Step 2: Create a scope
the-seed scopes add? Name for scope? my-project
? Your name? Jane Developer
? Your email? [email protected]
? Your URL? https://example.comThe scope @my-project is saved to your configuration.
Step 3: Create a component from a template
the-seed template component? Choose scope for component: @my-project
? Choose name for component: hello-worldThis creates the project directory at ~/the-seed/projects/@my-project/hello-world/ with autotools build files and a package.json containing build scripts.
Step 4: Install dependencies
cd ~/the-seed/projects/@my-project/hello-world
the-seed dependencies installChecking ecs-cpp... not installed
Cloning libecs-cpp...
Building libecs-cpp...
Checking the-seed... not installed
Cloning libthe-seed...
Building libthe-seed...This clones and builds the required C++ libraries into your prefix.
Step 5: Build the project
the-seed build nativeCompleted ./autogen.sh
Completed configure
Completed make
Completed make installThe compiled binary or library is installed to ~/the-seed/x86_64-linux-gnu/.
Directory Structure
After configuration and building, the installation prefix has the following layout:
~/the-seed/
+-- config.json # Configuration file (prefix, scopes)
+-- include/ # Shared headers
+-- projects/ # Scaffolded projects organized by scope
| +-- @scope-name/
| +-- project-name/
+-- x86_64-linux-gnu/ # Native Linux target
| +-- bin/ # Compiled binaries
| +-- lib/
| +-- pkgconfig/ # pkg-config files
+-- x86_64-w64-mingw32/ # Windows cross-compilation target
+-- bin/ # Cross-compiled binaries
+-- lib/
+-- pkgconfig/ # pkg-config filesCLI Reference
config
Manage the-seed configuration.
| Subcommand | Description |
|------------|-------------|
| list | Print the path to config.json and its contents (default) |
| edit | Interactively set the installation prefix |
| scopes list | Print the list of configured scope names |
| scopes help | Print help for config scopes subcommands |
the-seed config edit prompts:
? Installation prefix? ~/the-seedIf no config.json exists, config list suggests running config edit.
scopes
Manage project scopes. Scopes group projects under a namespace (e.g., @my-org).
| Subcommand | Description |
|------------|-------------|
| help | Print all subcommands with descriptions (default) |
| list | Print configured scope names |
| add | Interactively create a new scope |
| edit | Interactively edit an existing scope |
| delete | Interactively delete a scope |
the-seed scopes add prompts:
? Name for scope? my-project
? Your name? Jane Developer
? Your email? [email protected]
? Your URL? https://example.comScope names are automatically prefixed with @ if not already present.
the-seed scopes edit and scopes delete prompt you to select from existing scopes. If no scopes exist, an error message is printed.
template
Scaffold new C++ projects from built-in templates.
| Subcommand | Description |
|------------|-------------|
| help | List available templates (default) |
| component | Create a new ECS component project |
| system | Create a new ECS system project |
| program | Create a new standalone program project |
All three template types prompt for a scope and a project name:
? Choose scope for component: @my-project
? Choose name for component: hello-worldTemplate variable substitutions applied during scaffolding:
| Variable | Replaced With |
|----------|---------------|
| SKELETON | Project name |
| SKELETON_ | Project name with - replaced by _ |
| AUTHOR_EMAIL | Scope author email |
| AUTHOR_URL | Scope author URL |
The generated package.json includes build scripts:
{
"scripts": {
"build": "the-seed build native",
"build-win64": "the-seed build windows"
}
}The component and system templates include a .pc.in file for pkg-config. The program template does not.
build
Build and cross-compile projects using GNU Autotools.
| Subcommand | Arguments | Description |
|------------|-----------|-------------|
| help | | Print usage and available targets |
| native | | Full build for Linux (autogen, configure, make, install) |
| windows | | Full cross-compile for Windows (autogen, configure with mingw host, make, install) |
| (none) | | Incremental build (make + make install only, no reconfigure) |
Target directory mapping:
| Target | Host Flag | Install Prefix |
|--------|-----------|----------------|
| native | (none) | <prefix>/x86_64-linux-gnu |
| windows | --host=x86_64-w64-mingw32 | <prefix>/x86_64-w64-mingw32 |
During configure, PKG_CONFIG_PATH is set to <prefix>/<target>/lib/pkgconfig/ so that dependencies installed in the prefix are found.
Build steps for native and windows:
./autogen.shmake distclean(errors ignored)./configure --prefix=<prefix>/<target> [--host=x86_64-w64-mingw32]make -jmake install
Running the-seed build without a subcommand performs only steps 4 and 5.
dependencies
Check and install C++ library dependencies (libecs-cpp and libthe-seed).
| Subcommand | Arguments | Description |
|------------|-----------|-------------|
| help | | Print usage |
| check | [target] | Check if ecs-cpp and the-seed libraries are installed |
| install | [target] | Clone and build missing libraries from GitHub |
The target argument defaults to native. For each missing library, the install command clones the repository from GitHub and builds it with autotools into the target prefix:
ecs-cpp: Cloned fromhttps://github.com/metaverse-systems/libecs-cpp.gitthe-seed: Cloned fromhttps://github.com/metaverse-systems/libthe-seed.git
Running an unknown subcommand prints "Invalid command" with a pointer to help.
package
Create distributable packages by resolving binaries and their shared library dependencies.
Usage: the-seed package <output-directory> <project-dir> [project-dir2] ...| Argument | Description |
|----------|-------------|
| output-directory | Directory where resolved files are copied |
| project-dir | One or more project directories to package |
Behavior:
- Validates that all directories exist
- Parses
src/Makefile.amfor binary type (bin_PROGRAMSorlib_LTLIBRARIES) - Resolves compiled binaries from
src/.libs/ - Resolves transitive project dependencies from
package.jsonandnode_modules - Analyzes shared library dependencies using the native DependencyLister addon
- Copies all resolved files to the output directory
Search paths for shared library resolution include <prefix>/<target>/lib, <prefix>/<target>/bin, and MinGW cross-compiler runtime directories.
resource-pak
Create and manage resource pak files for bundling assets.
| Subcommand | Arguments | Description |
|------------|-----------|-------------|
| help | | List subcommands (default) |
| create | | Interactively create a new resource pak project |
| add | <resource-name> <filename> | Add a resource entry to the current project |
| build | | Build a .pak file from the current project |
the-seed resource-pak create prompts:
? Choose scope for resource pak: @my-project
? Choose name for resource pak: my-assetsThis creates a project directory at <prefix>/projects/<scope>/<name>/ with a package.json containing a resources array.
the-seed resource-pak add <name> <filename> reads package.json from the current directory and adds a resource entry with name, filename, and size. If a resource with the same name already exists, it is skipped.
the-seed resource-pak build reads package.json from the current directory and produces a .pak file. The file format consists of a JSON header (containing the name, a zero-padded 10-digit header size, and resource metadata) followed by a newline and the concatenated raw resource bytes.
API Reference
Classes
Config
Manages the-seed configuration file.
constructor(configDir?: string)Properties:
| Property | Type | Description |
|----------|------|-------------|
| configDir | string | Path to the configuration directory (default: ~/the-seed) |
| configFile | string | Configuration filename (/config.json) |
| config | ConfigType | The loaded configuration object |
Methods:
| Method | Return Type | Description |
|--------|-------------|-------------|
| loadConfig() | void | Load configuration from disk; creates default if missing |
| saveConfig() | void | Write current configuration to disk |
| getQuestions() | object[] | Return inquirer prompt questions for configuration |
| parseAnswers(answers: { prefix: string }) | void | Apply prompt answers to the configuration |
Scopes
Manages project scopes within the configuration.
constructor(config: Config)Properties:
| Property | Type | Description |
|----------|------|-------------|
| config | Config | The Config instance to read/write scopes from |
Methods:
| Method | Return Type | Description |
|--------|-------------|-------------|
| askWhichScope() | object[] | Return inquirer prompt to select an existing scope |
| askNewScope() | object[] | Return inquirer prompts for creating a new scope |
| askEditScope(defaults?: ScopeDefaultsType) | object[] | Return inquirer prompts for editing a scope |
| createOrEditScope(answers: ScopeAnswersType) | void | Save a scope from prompt answers |
| deleteScope(scope: string) | void | Remove a scope from configuration |
| getScopes() | string[] | Return array of scope names |
| getScope(scope: string) | ScopeType | Return a specific scope by name |
| getQuestions(defaults: { scopeName?: string }) | object[] | Return inquirer prompts with optional defaults |
Package
Resolves project binaries and their shared library dependencies for packaging.
constructor(config: Config)Properties:
| Property | Type | Description |
|----------|------|-------------|
| config | Config | The Config instance for prefix and target paths |
Methods:
| Method | Return Type | Description |
|--------|-------------|-------------|
| getSearchPaths() | string[] | Return library search paths for the current target |
| parseMakefileAm(projectDir: string) | { type: "program" \| "library"; name: string } \| null | Parse src/Makefile.am for binary type and name |
| resolveBinaryPaths(projectDir: string) | string[] | Resolve compiled binary paths from src/.libs/ |
| getPackageDeps(projectDir: string, visited?: Set<string>) | string[] | Recursively resolve project dependencies |
| resolveDependencies(binaryPaths: string[], searchPaths: string[]) | DependencyResultType | Analyze shared library dependencies using native addon |
| run(outputDir: string, projectDirs: string[]) | void | Execute full packaging workflow |
Types
interface AuthorType {
name: string;
email: string;
url: string;
}
interface ConfigType {
prefix: string;
scopes: ScopesType;
}
interface ScopeType {
author: AuthorType;
}
interface ScopesType {
[index: string]: ScopeType;
}
interface ScopeAnswersType {
scopeName: string;
authorName: string;
authorEmail: string;
authorURL: string;
}
interface ScopeDefaultsType {
name?: string;
email?: string;
url?: string;
}
interface ResourceType {
name: string;
filename: string;
size: number;
attributes?: { [key: string]: string };
}
interface PackageType {
author: AuthorType;
name: string;
license: string;
version: string;
scripts: {
[index: string]: string;
};
resources: ResourceType[];
main?: string;
}
interface ScriptArgsType {
binName: string;
args: string[];
configDir: string;
}
interface DependencyResultType {
dependencies: Record<string, string[]>;
errors: Record<string, string>;
}Import Example
import {
Config,
Scopes,
Package,
AuthorType,
ConfigType,
ScopeType,
ScopesType,
ScopeAnswersType,
ScopeDefaultsType,
ResourceType,
PackageType,
ScriptArgsType,
DependencyResultType
} from "@metaverse-systems/the-seed";
// Initialize configuration
const config = new Config();
// List all scopes
const scopes = new Scopes(config);
console.log(scopes.getScopes());
// Package a project
const pkg = new Package(config);
pkg.run("./output", ["./my-project"]);License
MIT -- See LICENSE for details.
Author
Tim Schwartz [email protected]
