FERRETGame engine over Babylon.js
Ferret

@ferret/compiler

The compiler core: a .fprj project's files in, a .fex game and a report out. It touches no disk and no network: the bundler (esbuild, native or wasm), the release's release.json and the engi…

The compiler core: a .fprj project's files in, a .fex game and a report out. It touches no disk and no network: the bundler (esbuild, native or wasm), the release's release.json and the engine files are handed in, so the same code runs in ferret build and in the browser editor, and the same project gives the same bytes in both.

24 exports · source in packages/compiler/src

Classes

BuildError class

class BuildError extends Error
constructor(message: string, readonly issues: { path: string; message: string }[] = [])

packages/compiler/src/index.ts:103

Functions

babylonPartsFor function

function babylonPartsFor(names: Iterable<string>, parts: BabylonParts): string[]

The parts of Babylon that cover these names, with the parts they imply, core first.

packages/compiler/src/index.ts:24

buildGame function

async function buildGame(files: Map<string, Uint8Array>, env: BuildEnv, o: BuildOptions = {}): Promise<{ bytes: Uint8Array; manifest: PackageManifest; report: BuildReport }>

Build a game from a project. files are the project's files by path (including ferret.json). Returns the .fex bytes and the report; throws a BuildError, with the issues and without any output, when the project or the result does not check out.

packages/compiler/src/index.ts:160

buildLevelPackage function

async function buildLevelPackage(files: Map<string, Uint8Array>, env: Pick<BuildEnv, 'release'>, o: LevelPackageOptions): Promise<{ bytes: Uint8Array; manifest: PackageManifest; report: LevelPackageReport }>

A package of kind levels for a finished game: the chosen levels and the assets they name, no code, for the game. Assets the game's .fex already holds (alreadyIn) stay out. Throws a BuildError, without output, when the result does not check out.

packages/compiler/src/index.ts:329

checkProject function

async function checkProject(files: Map<string, Uint8Array>, engine: { ferret: string; babylon: string }): Promise<CheckResult>

Open a project from its bytes (or files) and check everything that needs no build: the manifest, the levels, every reference.

packages/compiler/src/index.ts:291

ferretSourceIssues function

function ferretSourceIssues(files: Map<string, Uint8Array>): { path: string; message: string }[]

the plan requirement 9: a project holds the user's own code and assets, never a copy of Ferret or Babylon. They are met at run time only. Returns what in the project looks like engine material: an engine/ folder, node_modules, an engine or Babylon bundle by name or by content.

packages/compiler/src/index.ts:141

globMatch function

function globMatch(pattern: string, path: string): boolean

Does a keep / .ferretignore pattern (*, **, ?) match this path?

packages/compiler/src/index.ts:111

projectBundle function

function projectBundle(esbuild: EsbuildLike)

packages/compiler/src/bundle.ts:21

selectEngine function

function selectEngine(release: ReleaseJson, names: string[], wanted: Record<string, string> = {}): EngineSelection

The part of a release the given modules need: their files, the chunks those import (statically or dynamically), and the run-time files.

packages/compiler/src/index.ts:47

Interfaces

BabylonParts interface

interface BabylonParts

parts.json of a Babylon-in-parts folder (tools/babylon/build.mjs): the name -> part map and what a part implies

babylon: string
names: Record<string, string>
implies: Record<string, string[]>
parts: Record<string, { file: string; bytes: number; graphBytes: number; chunks: string[]; /** files it may fetch later by `import()` */ dynamic?: string[] }>

packages/compiler/src/index.ts:21

BuildEnv interface

interface BuildEnv
bundle(entry: string, files: Map<string, Uint8Array>): Promise<BundleResult>bundle entry (a path in files) as one ES module: relative imports resolved in files, @ferret/* and nothing else left external
release: ReleaseJson
readRelease?(path: string): Promise<Uint8Array>standalone only: the bytes of a file of the release folder (modules/<v>/<path>), and Babylon's files by their names
babylonFiles?(): Promise<{ name: string; data: Uint8Array }[]>
babylonParts?: BabylonPartsBabylon in parts (stage P6): its parts.json and the bytes of a file of that folder. Without it the game names no parts and the player loads the full build
readBabylonPart?(file: string): Promise<Uint8Array>

packages/compiler/src/index.ts:77

BuildOptions interface

interface BuildOptions
standalone?: boolean

packages/compiler/src/index.ts:89

BuildReport interface

interface BuildReport
game: { id: string; version: string; bytes: number; standalone: boolean }
engine: { ferret: string; babylon: string; modules: { name: string; why: string; bytes: number }[]; files: { path: string; bytes: number }[]; bytes: number; where: 'host' | 'inside' }
included: ReportFile[]what the game reaches and carries, by folder
left: { path: string; bytes: number }[]project files nothing reaches
levels: Record<string, { files: number; bytes: number }>per level: its files

packages/compiler/src/index.ts:92

BundleResult interface

interface BundleResult
code: string
imports: { name: string; from: string }[]

packages/compiler/src/index.ts:75

CheckResult interface

interface CheckResult
issues: { path: string; message: string }[]
warnings: { path: string; message: string }[]

packages/compiler/src/index.ts:288

EngineSelection interface

interface EngineSelection
modules: string[]every module of the closure, with the file sizes it adds
files: string[]every file of the release folder this needs, sorted: module files, chunks, runtime files
babylon: string[]the Babylon names the modules need at load, and the ones they ask for later
babylonLazy: string[]
release: ReleaseJsona release.json cut to exactly these files
why: Record<string, string>why each module is in: the import that wants it, or always

packages/compiler/src/index.ts:33

EsbuildLike interface

interface EsbuildLike

The part of esbuild's API this uses; esbuild and esbuild-wasm both fit.

build(options: Record<string, unknown>): Promise<{ outputFiles?: { text: string }[]; metafile?: { inputs: Record<string, { imports: { path: string }[] }> } }>

packages/compiler/src/bundle.ts:9

LevelPackageOptions interface

interface LevelPackageOptions
levels: string[]the level ids to ship
id?: stringpackage id, name and version; defaults <game>-levels, <game name> levels, the project's version
name?: string
version?: string
forVersion?: stringwhich versions of the game it fits; default ^<project version>
alreadyIn?: Iterable<string>paths the game's .fex already holds (its report.json, or the list of its files): not copied again

packages/compiler/src/index.ts:313

LevelPackageReport interface

interface LevelPackageReport
id: string
version: string
bytes: number
levels: Record<string, { files: number; bytes: number }>
included: ReportFile[]
skipped: { path: string; why: string }[]

packages/compiler/src/index.ts:323

ReleaseChunk interface

interface ReleaseChunk
bytes: number
sha256: string
imports: string[]
dynamic?: string[]

packages/compiler/src/index.ts:12

ReleaseJson interface

interface ReleaseJson
format: number
ferret: string
build: string
babylon: string
modules: Record<string, ReleaseModule>
chunks: Record<string, ReleaseChunk>
runtime: Record<string, { bytes: number; sha256: string; module: string }>

packages/compiler/src/index.ts:13

ReleaseModule interface

interface ReleaseModule
file: string
bytes: number
sha256: string
chunks: string[]
imports: string[]
graphBytes: number
runtime: string[]
babylon?: string[]
babylonLazy?: string[]

packages/compiler/src/index.ts:11

ReportFile interface

interface ReportFile
path: string
bytes: number
why: string

packages/compiler/src/index.ts:91

Constants

ALWAYS_LOADED const

const ALWAYS_LOADED: string[]

What the player always loads, whatever the game imports: the boot module and the player itself.

packages/compiler/src/index.ts:31