ABout to try scene and script merger

This commit is contained in:
2026-06-02 16:46:39 -05:00
parent 241a52b94a
commit 2b3abbe13b
36 changed files with 1137 additions and 419 deletions
+86
View File
@@ -0,0 +1,86 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
/**
* Descriptor for one entry in an `AssetBatch`.
*
* `format` — texture format constant (`Texture.FORMAT_*`). Alias for `input`
* when the type is `Asset.TYPE_TEXTURE`.
* `axis` — mesh axis constant (`Asset.MESH_AXIS_*`). Alias for `input`
* when the type is `Asset.TYPE_MESH`.
* `input` — generic numeric input for all other loader types.
*/
interface AssetBatchDescriptor {
path: string;
type: number;
format?: number;
axis?: number;
input?: number;
}
/** A group of asset entries locked and queued for loading together. */
interface AssetBatch {
/** Number of entries in the batch. */
readonly count: number;
/** `true` when every entry has reached `LOADED`. */
readonly isLoaded: boolean;
/** `true` if any entry is in an `ERROR` state. */
readonly hasError: boolean;
/**
* Blocks until every entry is loaded.
* Returns `this` for chaining.
* @throws If any entry fails to load.
*/
requireLoaded(): this;
/**
* Acquires one additional lock on every entry.
* Returns `this` for chaining.
*/
lock(): this;
/**
* Releases all locks and clears the batch.
* After this call the object is invalid — do not use it again.
*/
unlock(): void;
/**
* Returns the `AssetEntry` at `index`, adding an independent lock.
* The returned entry must be unlocked separately when no longer needed.
* Returns `undefined` if `index` is out of range or the batch is disposed.
*/
entry(index: number): AssetEntry | undefined;
/**
* Fires once when every entry has loaded successfully.
* Subscribe with `onLoaded[0] = () => { ... }`.
*/
readonly onLoaded: AssetEventProxy;
/**
* Fires each time a single entry finishes loading.
* Subscribe with `onEntryLoaded[0] = () => { ... }`.
*/
readonly onEntryLoaded: AssetEventProxy;
/**
* Fires once when all entries have finished but at least one errored.
* Subscribe with `onError[0] = () => { ... }`.
*/
readonly onError: AssetEventProxy;
/**
* Fires each time a single entry transitions to an error state.
* Subscribe with `onEntryError[0] = () => { ... }`.
*/
readonly onEntryError: AssetEventProxy;
toString(): string;
}
interface AssetBatchConstructor {
/** Creates a batch from an array of descriptors. Works with or without `new`. */
(descriptors: AssetBatchDescriptor[]): AssetBatch;
new(descriptors: AssetBatchDescriptor[]): AssetBatch;
}
declare var AssetBatch: AssetBatchConstructor;
+24
View File
@@ -5,6 +5,24 @@
* https://opensource.org/licenses/MIT
*/
/**
* An array-like proxy over one of an asset entry's events.
* Assign a function to a numbered slot to subscribe; assign `null` to
* unsubscribe that slot.
*
* @example
* entry.onLoaded[0] = () => Console.print('loaded!');
* entry.onLoaded[0] = null; // unsubscribe
*/
interface AssetEventProxy {
readonly length: number;
0: (() => void) | null;
1: (() => void) | null;
2: (() => void) | null;
3: (() => void) | null;
toString(): string;
}
/**
* A live reference to an entry in the asset cache.
* Holds a lock that keeps the entry alive; the lock is released automatically
@@ -26,6 +44,12 @@ interface AssetEntry {
* is not yet loaded.
*/
readonly texture: Texture | undefined;
/** Event proxy — subscribe up to 4 callbacks for when loading completes. */
readonly onLoaded: AssetEventProxy;
/** Event proxy — subscribe up to 4 callbacks for when the entry is disposed. */
readonly onUnloaded: AssetEventProxy;
/** Event proxy — subscribe up to 4 callbacks for when loading fails. */
readonly onError: AssetEventProxy;
/**
* Blocks until the entry reaches `LOADED` (or `ERROR`).
* Returns `this` for chaining.
+4
View File
@@ -14,6 +14,9 @@
* { "compilerOptions": { "typeRoots": ["./types"] } }
*/
// module system
/// <reference path="./require.d.ts" />
// math
/// <reference path="./math/vec3.d.ts" />
@@ -24,6 +27,7 @@
// asset
/// <reference path="./asset/assetentry.d.ts" />
/// <reference path="./asset/assetbatch.d.ts" />
/// <reference path="./asset/asset.d.ts" />
// engine systems
+69
View File
@@ -0,0 +1,69 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
/**
* CommonJS-style module loader. Accepts a single path or an array of paths.
*
* - Single string → returns that module's `exports`.
* - Array of strings → returns an array of `exports` in the same order.
*
* Modules are cached after their first load. Subsequent calls with the same
* resolved path return the cached exports without re-executing the file.
*
* Path rules: `"./foo"` / `"../foo"` resolve relative to the calling script's
* directory; any other string resolves from the archive root. `.js` is
* appended automatically when missing.
*
* @example
* const NPC = require('./entities/NPC');
* const [NPC, Item] = require(['./entities/NPC', './entities/Item']);
*/
declare function require(path: string): any;
declare function require(paths: string[]): any[];
/**
* Asynchronous module loader. Accepts a single path or an array of paths.
* The asset file(s) are read in the background; once all are loaded and
* evaluated, `callback` is invoked.
*
* - Single string → `callback(exports)` — first argument is the module's
* `exports`, or `null` on load failure.
* - Array of strings → `callback(exportsArray)` — first argument is an array
* of `exports` values in the same order; failed entries are `null`.
*
* Cached modules resolve synchronously (callback fires on the same call).
* Path rules are identical to `require`.
*
* @example
* requireAsync('./entities/NPC', function(NPC) {
* if(NPC) NPC.init();
* });
*
* requireAsync(['./entities/NPC', './entities/Item'], function(mods) {
* const [NPC, Item] = mods;
* });
*/
declare function requireAsync(
path: string,
callback: (exports: any) => void
): void;
declare function requireAsync(
paths: string[],
callback: (exports: any[]) => void
): void;
/**
* The module object for the currently executing script.
* Assign `module.exports` to control what `require()` returns to callers.
*/
declare var module: { exports: any };
/**
* Shorthand for `module.exports`. Direct assignment (`exports = ...`) does
* NOT update `module.exports`; use `module.exports = ...` for that.
*/
declare var exports: any;
+37 -11
View File
@@ -5,23 +5,49 @@
* https://opensource.org/licenses/MIT
*/
/** Scene management — request scene transitions and query the active scene. */
/**
* The object a JS scene module must export.
* All methods are optional.
*
* @example
* // assets/scenes/game.js
* var scene = {};
* var batch = AssetBatch([{ path: 'tex/bg.png', type: Asset.TYPE_TEXTURE }]);
*
* scene.load = function() { return batch; };
* scene.init = function() { Console.print('scene started'); };
* scene.update = function() { /* per-frame logic *\/ };
* scene.dispose = function() { batch.unlock(); };
*
* module.exports = scene;
*/
interface SceneObject {
/** Return an AssetBatch to preload before init is called. Optional. */
load?(): AssetBatch | undefined;
/** Called when this scene becomes active. Optional. */
init?(): void;
/** Called every frame while this scene is active. Optional. */
update?(): void;
/** Called when the scene is replaced or the engine shuts down. Optional. */
dispose?(): void;
}
/** Scene management. */
interface SceneNamespace {
/** Type constant of the currently active scene, or 0 if none. */
readonly current: number;
/** `true` while a JS script scene is running. */
readonly active: boolean;
/**
* Requests a scene transition. The change takes effect at the start of the
* next safe update tick (current scene is disposed, new scene is initialized).
* Loads the JS module at `path`, waits for any `AssetBatch` returned by
* `scene.load()`, then activates the scene (calling `scene.init()`).
* The previous scene's `dispose()` is called just before `init()`.
*
* Returns immediately — the transition is asynchronous.
*
* @example
* Scene.set(Scene.OVERWORLD);
* Scene.set('assets/scenes/game.js');
*/
set(type: number): void;
readonly INITIAL: number;
readonly TEST: number;
readonly OVERWORLD: number;
set(path: string): void;
}
declare var Scene: SceneNamespace;