littlejsengine 1.20.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,10 @@ declare module "littlejsengine" {
7
7
  * - Called after the engine starts, can be async
8
8
  */
9
9
  export type GameInitCallback = () => void | Promise<void>;
10
+ /**
11
+ * - Draws the loading screen on mainContext, each frame while the game loads
12
+ */
13
+ export type LoadingScreenCallback = (progress: number) => any;
10
14
  /**
11
15
  * - Update or render function for the game
12
16
  */
@@ -76,6 +80,10 @@ declare module "littlejsengine" {
76
80
  */
77
81
  object?: any;
78
82
  };
83
+ /**
84
+ * - Called once when a SpriteAnimation's play ends
85
+ */
86
+ export type SpriteAnimationEndCallback = () => void;
79
87
  /**
80
88
  * - Function called when sound is loaded
81
89
  */
@@ -88,6 +96,73 @@ declare module "littlejsengine" {
88
96
  * - Decides whether a particle stops at a tile, it is a filter rather than a notice
89
97
  */
90
98
  export type ParticleCollideCallback = (particle: Particle, tileData: number, pos: Vector2) => boolean;
99
+ /**
100
+ * A scene, any object with the hooks it needs, each optional and called as a method so this is the scene
101
+ */
102
+ export type Scene = {
103
+ /**
104
+ * - Called when the scene starts, after the old one left and the objects were destroyed
105
+ */
106
+ enter?: () => void;
107
+ /**
108
+ * - Called before the next scene starts, while the scene is current and its objects are still there
109
+ */
110
+ leave?: () => void;
111
+ /**
112
+ * - Called each update after gameUpdate, not while paused or at time scale 0
113
+ */
114
+ update?: () => void;
115
+ /**
116
+ * - Called before gameRender, to draw under the objects
117
+ */
118
+ render?: () => void;
119
+ /**
120
+ * - Called after gameRenderPost, to draw over the game, while paused too; plugins made after the first setScene draw over it
121
+ */
122
+ renderPost?: () => void;
123
+ };
124
+ /**
125
+ * A particle as a ParticleEmitter3D's callbacks see it: one object the emitter reuses, set from the particle for each
126
+ * call and written back after it, so copy what you keep
127
+ */
128
+ export type Particle3D = {
129
+ /**
130
+ * - The emitter it is in
131
+ */
132
+ emitter: ParticleEmitter3D;
133
+ /**
134
+ * - Where it is, change it to move it
135
+ */
136
+ pos: Vector3;
137
+ /**
138
+ * - How far it moves each frame
139
+ */
140
+ velocity: Vector3;
141
+ /**
142
+ * - Seconds it has lived
143
+ */
144
+ age: number;
145
+ /**
146
+ * - Seconds it lives
147
+ */
148
+ lifeTime: number;
149
+ /**
150
+ * - Set by destroy
151
+ */
152
+ destroyed: boolean;
153
+ /**
154
+ * - End it this update, the destroy callback gets it
155
+ */
156
+ destroy: () => void;
157
+ };
158
+ /**
159
+ * - A function a ParticleEmitter3D calls with one of its particles
160
+ */
161
+ export type Particle3DCallback = (particle: Particle3D) => any;
162
+ /**
163
+ * - Decides whether a particle stops where it hits the level, a filter as in 2D
164
+ */
165
+ export type Particle3DCollideCallback = (particle: Particle3D, level: EngineObject3D, pos: Vector3) => boolean | void;
91
166
  /**
92
167
  * What VoxelMap.raycast finds: how far along the ray, the block's cell and type, and the normal of the face it comes in
93
168
  * through
@@ -146,11 +221,12 @@ declare module "littlejsengine" {
146
221
  * @default
147
222
  * @memberof Engine */
148
223
  export const frameRate: number;
149
- /** How many seconds each frame lasts, engine uses a fixed time step
224
+ /** How many seconds the update covers: 1/60 with the fixed time step, or with engineVariableStep the time of the
225
+ * display frame it runs on, times timeScale; while paused it keeps the last update's
150
226
  * @type {number}
151
227
  * @default 1/60
152
228
  * @memberof Engine */
153
- export const timeDelta: number;
229
+ export let timeDelta: number;
154
230
  /** Array containing all engine objects
155
231
  * @type {Array<EngineObject>}
156
232
  * @memberof Engine */
@@ -189,6 +265,11 @@ declare module "littlejsengine" {
189
265
  * @return {void|Promise<void>}
190
266
  * @memberof Engine
191
267
  */
268
+ /**
269
+ * @callback LoadingScreenCallback - Draws the loading screen on mainContext, each frame while the game loads
270
+ * @param {number} progress - The part of the loads done, 0 to 1
271
+ * @memberof Engine
272
+ */
192
273
  /**
193
274
  * @callback GameCallback - Update or render function for the game
194
275
  * @memberof Engine
@@ -284,6 +365,15 @@ declare module "littlejsengine" {
284
365
  * @param {PluginCallback} [preRender] - Called after the canvas is cleared and before gameRender
285
366
  * @memberof Engine */
286
367
  export function engineAddPlugin(update?: PluginCallback, render?: PluginCallback, glContextLost?: PluginCallback, glContextRestored?: PluginCallback, preRender?: PluginCallback): void;
368
+ /** Add something the game loads to what startup waits for: while engineInit and gameInit run, the game loop starts
369
+ * once it is done, and the loading screen counts it; images from loadTexture and sounds from files are added on
370
+ * their own, and a load that fails counts as done; after startup it does nothing
371
+ * @param {Promise<any>} promise
372
+ * @return {Promise<any>} - The same promise
373
+ * @example
374
+ * async function gameInit() { level = await engineAddLoad(fetchJSON('level.json')); }
375
+ * @memberof Engine */
376
+ export function engineAddLoad(promise: Promise<any>): Promise<any>;
287
377
  /**
288
378
  * LittleJS Debug System
289
379
  * - Press Esc to toggle debug overlay with object picking
@@ -532,6 +622,12 @@ declare module "littlejsengine" {
532
622
  * @default
533
623
  * @memberof Settings */
534
624
  export let showSplashScreen: boolean;
625
+ /** The loading screen, drawn after the splash while the images, gameInit and what they load are loading, once that
626
+ * takes more than half a second: a function given the part done, 0 to 1, or undefined for none, which leaves the
627
+ * screen blank; the default says Loading over a bar
628
+ * @type {LoadingScreenCallback|undefined}
629
+ * @memberof Settings */
630
+ export let loadingScreen: LoadingScreenCallback | undefined;
535
631
  /** Disables all rendering, audio, and input for servers, must be set before engineInit
536
632
  * @type {boolean}
537
633
  * @default
@@ -543,6 +639,14 @@ declare module "littlejsengine" {
543
639
  * @default
544
640
  * @memberof Settings */
545
641
  export let engineManualStep: boolean;
642
+ /** Run one update per display frame with timeDelta the time it covers, in place of fixed updates at frameRate
643
+ * - Per-frame values are not scaled: velocity, gravity, damping and particle speeds act once per update, so a
644
+ * game that turns this on scales its own movement by timeDelta
645
+ * - Values in seconds follow real time as they are: time, timers, particle emit rate and life, animation, Box2D
646
+ * @type {boolean}
647
+ * @default
648
+ * @memberof Settings */
649
+ export let engineVariableStep: boolean;
546
650
  /** Default size of tiles in pixels
547
651
  * @type {Vector2}
548
652
  * @default Vector2(16,16)
@@ -854,6 +958,10 @@ declare module "littlejsengine" {
854
958
  * @param {boolean} show
855
959
  * @memberof Settings */
856
960
  export function setShowSplashScreen(show: boolean): void;
961
+ /** Set the loading screen, drawn after the splash while the game loads, once that takes more than half a second
962
+ * @param {LoadingScreenCallback} [callback] - Draws on mainContext given the part done, 0 to 1; undefined for none
963
+ * @memberof Settings */
964
+ export function setLoadingScreen(callback?: LoadingScreenCallback): void;
857
965
  /** Set to disable rendering, audio, and input for servers, must be set before engineInit
858
966
  * @param {boolean} headless
859
967
  * @memberof Settings */
@@ -864,6 +972,11 @@ declare module "littlejsengine" {
864
972
  * @param {boolean} [enable]
865
973
  * @memberof Settings */
866
974
  export function setEngineManualStep(enable?: boolean): void;
975
+ /** Set if the engine runs one update per display frame with timeDelta the time it covers
976
+ * Can be set before engineInit or while running; turned off it goes back to fixed updates at frameRate
977
+ * @param {boolean} [enable]
978
+ * @memberof Settings */
979
+ export function setEngineVariableStep(enable?: boolean): void;
867
980
  /** Set if WebGL rendering is enabled
868
981
  * @param {boolean} enable
869
982
  * @memberof Settings */
@@ -2006,12 +2119,19 @@ declare module "littlejsengine" {
2006
2119
  * @return {Promise<TextureInfo>} Resolves to the texture info once the image loads, or fails to with a warning
2007
2120
  * @memberof Draw */
2008
2121
  export function loadTexture(textureIndex: number, src?: string): Promise<TextureInfo>;
2122
+ /**
2123
+ * @callback SpriteAnimationEndCallback - Called once when a SpriteAnimation's play ends
2124
+ * @return {void}
2125
+ * @memberof Draw
2126
+ */
2009
2127
  /**
2010
2128
  * SpriteAnimation - Steps a tile through its frames over time: looping, once, or there and back
2011
2129
  * - Driven by the engine time like a Timer, so it pauses with the game and needs no update call
2012
2130
  * - Read tileInfo each frame for the frame to draw, from an object's update or before a drawTile
2013
2131
  * - loop, play and pingPong each start over from the first frame; stop holds the current one
2132
+ * - play(onEnd) calls onEnd once the play ends, on the first read after it, since there is no update to call it
2014
2133
  * - Frames follow each other along the row, as tileInfo.frame counts them
2134
+ * - SpriteAnimator switches between a character's animations by name
2015
2135
  * @example
2016
2136
  * const walk = new SpriteAnimation(tile(0, 16), 4, .1); // four frames, a tenth of a second each
2017
2137
  * const attack = new SpriteAnimation(tile(4, 16), 3, .05).play(); // once, then holds the last frame
@@ -2039,19 +2159,23 @@ declare module "littlejsengine" {
2039
2159
  /** @property {number|undefined} - The frame held by stop, undefined while running
2040
2160
  * @type {number|undefined} */
2041
2161
  heldFrame: number | undefined;
2162
+ /** @property {SpriteAnimationEndCallback|undefined} - Called once when a play ends, on the first read after it
2163
+ * @type {SpriteAnimationEndCallback|undefined} */
2164
+ onEnd: SpriteAnimationEndCallback | undefined;
2042
2165
  /** Start over from the first frame and repeat forever
2043
2166
  * @return {SpriteAnimation} */
2044
2167
  loop(): SpriteAnimation;
2045
2168
  /** Start over from the first frame, run through once and hold the last frame, last to first at a negative speed
2169
+ * @param {function():void} [onEnd] - Called once when it ends, on the first read of it after that
2046
2170
  * @return {SpriteAnimation} */
2047
- play(): SpriteAnimation;
2171
+ play(onEnd?: () => void): SpriteAnimation;
2048
2172
  /** Start over from the first frame and run there and back forever
2049
2173
  * @return {SpriteAnimation} */
2050
2174
  pingPong(): SpriteAnimation;
2051
2175
  /** Hold the current frame
2052
2176
  * @return {SpriteAnimation} */
2053
2177
  stop(): SpriteAnimation;
2054
- /** Start over from the first frame in a mode
2178
+ /** Start over from the first frame in a mode, with no end callback
2055
2179
  * @param {string} [mode] - 'loop', 'once' or 'pingPong', the current mode when left out
2056
2180
  * @return {SpriteAnimation} */
2057
2181
  restart(mode?: string): SpriteAnimation;
@@ -2064,7 +2188,52 @@ declare module "littlejsengine" {
2064
2188
  /** The tile of the frame showing now
2065
2189
  * @return {TileInfo} */
2066
2190
  get tileInfo(): TileInfo;
2067
- /** True once a play has shown its last frame for its time
2191
+ /** True once a play has shown its last frame for its time, the first read after that calls onEnd
2192
+ * @return {boolean} */
2193
+ get isDone(): boolean;
2194
+ }
2195
+ /**
2196
+ * SpriteAnimator - A character's animations by name, like idle, walk and attack, and the one showing now
2197
+ * - Each clip is a SpriteAnimation and keeps its own mode, loop, play or pingPong
2198
+ * - set starts a clip over only when it changes or a play of it has ended, so it can be called every update
2199
+ * - Read tileInfo each frame for the frame to draw, as with a SpriteAnimation
2200
+ * @example
2201
+ * const hero = new SpriteAnimator({
2202
+ * idle: new SpriteAnimation(tile(0, 16), 2, .4),
2203
+ * walk: new SpriteAnimation(tile(2, 16), 4, .1),
2204
+ * attack: new SpriteAnimation(tile(6, 16), 3, .05).play(),
2205
+ * });
2206
+ * hero.set('attack', ()=> hero.set('idle')); // back to idle when the attack ends
2207
+ * // in update: this.tileInfo = hero.tileInfo;
2208
+ * @memberof Draw
2209
+ */
2210
+ export class SpriteAnimator {
2211
+ /** Create an animator from its clips, showing the first one
2212
+ * @param {Object<string, SpriteAnimation>} clips - The clips by name */
2213
+ constructor(clips: {
2214
+ [x: string]: SpriteAnimation;
2215
+ });
2216
+ /** @property {Object<string, SpriteAnimation>} - The clips by name */
2217
+ clips: {
2218
+ [x: string]: SpriteAnimation;
2219
+ };
2220
+ /** @property {string} - The name of the clip showing now */
2221
+ name: string;
2222
+ /** Show a clip, starting it over in its own mode unless it is showing and has not ended
2223
+ * @param {string} name - The clip's name
2224
+ * @param {function():void} [onEnd] - Called once when a play clip ends, as with SpriteAnimation.play
2225
+ * @return {SpriteAnimator} */
2226
+ set(name: string, onEnd?: () => void): SpriteAnimator;
2227
+ /** The clip showing now
2228
+ * @return {SpriteAnimation} */
2229
+ get clip(): SpriteAnimation;
2230
+ /** The tile of the frame showing now
2231
+ * @return {TileInfo} */
2232
+ get tileInfo(): TileInfo;
2233
+ /** The frame of the clip showing now
2234
+ * @return {number} */
2235
+ get frame(): number;
2236
+ /** True once the clip showing now is a play that has ended
2068
2237
  * @return {boolean} */
2069
2238
  get isDone(): boolean;
2070
2239
  }
@@ -6788,6 +6957,16 @@ declare module "littlejsengine" {
6788
6957
  function PIECEWISE(...fns: ((arg0: number) => number)[]): (arg0: number) => number;
6789
6958
  function BEZIER(x1: number, y1: number, x2: number, y2: number): (arg0: number) => number;
6790
6959
  }
6960
+ /** Leave the current scene, destroy every object that is not persistent, and enter the next scene
6961
+ * - Setting the current scene again restarts it, and no scene leaves the game with none
6962
+ * - The switch happens at once, it can be called from anywhere but a scene's leave
6963
+ * @param {Scene} [scene] - The scene to enter
6964
+ * @memberof SceneSystem */
6965
+ export function setScene(scene?: Scene): void;
6966
+ /** Get the current scene
6967
+ * @return {Scene|undefined}
6968
+ * @memberof SceneSystem */
6969
+ export function getScene(): Scene | undefined;
6791
6970
  /** Grid pathfinder using A* with two optional smoothing passes.
6792
6971
  * @memberof PathFinding
6793
6972
  * @example
@@ -7363,24 +7542,27 @@ declare module "littlejsengine" {
7363
7542
  */
7364
7543
  export function buildMatrix(pos?: Vector3, rotation?: Vector3, scale?: Vector3, matrix?: Matrix4): Matrix4;
7365
7544
  /**
7366
- * Check if a point is inside an axis aligned box, boundary is inclusive
7545
+ * Check if a point is inside a box, boundary is inclusive
7367
7546
  * @param {Vector3} point
7368
7547
  * @param {Vector3} pos - Center of the box
7369
7548
  * @param {Vector3} size - Full size of the box
7549
+ * @param {Vector3} [rotation] - How the box is turned, upright when left out
7370
7550
  * @return {boolean}
7371
7551
  * @memberof Math3D
7372
7552
  */
7373
- export function isPointInBox3D(point: Vector3, pos: Vector3, size: Vector3): boolean;
7553
+ export function isPointInBox3D(point: Vector3, pos: Vector3, size: Vector3, rotation?: Vector3): boolean;
7374
7554
  /**
7375
- * Check if two axis aligned boxes are overlapping, touching edges do not overlap
7555
+ * Check if two boxes are overlapping, touching edges do not overlap
7376
7556
  * @param {Vector3} posA
7377
7557
  * @param {Vector3} sizeA - Full size of box A
7378
7558
  * @param {Vector3} posB
7379
7559
  * @param {Vector3} [sizeB] - Full size of box B, zero for a point
7560
+ * @param {Vector3} [rotationA] - How box A is turned, upright when left out
7561
+ * @param {Vector3} [rotationB] - How box B is turned
7380
7562
  * @return {boolean}
7381
7563
  * @memberof Math3D
7382
7564
  */
7383
- export function isOverlapping3D(posA: Vector3, sizeA: Vector3, posB: Vector3, sizeB?: Vector3): boolean;
7565
+ export function isOverlapping3D(posA: Vector3, sizeA: Vector3, posB: Vector3, sizeB?: Vector3, rotationA?: Vector3, rotationB?: Vector3): boolean;
7384
7566
  /**
7385
7567
  * Returns the vector to move sphere A by so it no longer overlaps sphere B, or undefined
7386
7568
  * @param {Vector3} posA
@@ -7392,15 +7574,16 @@ declare module "littlejsengine" {
7392
7574
  */
7393
7575
  export function collideSphereSphere(posA: Vector3, radiusA: number, posB: Vector3, radiusB: number): Vector3 | undefined;
7394
7576
  /**
7395
- * Returns the vector to move a sphere out of an axis aligned box, or undefined
7577
+ * Returns the vector to move a sphere out of a box, or undefined
7396
7578
  * @param {Vector3} pos - Sphere center
7397
7579
  * @param {number} radius
7398
7580
  * @param {Vector3} boxPos
7399
7581
  * @param {Vector3} boxSize - Full size of the box
7582
+ * @param {Vector3} [boxRotation] - How the box is turned, upright when left out
7400
7583
  * @return {Vector3|undefined}
7401
7584
  * @memberof Math3D
7402
7585
  */
7403
- export function collideSphereBox(pos: Vector3, radius: number, boxPos: Vector3, boxSize: Vector3): Vector3 | undefined;
7586
+ export function collideSphereBox(pos: Vector3, radius: number, boxPos: Vector3, boxSize: Vector3, boxRotation?: Vector3): Vector3 | undefined;
7404
7587
  /**
7405
7588
  * Returns the vector to move a sphere back inside an axis aligned box, or undefined when it is all inside
7406
7589
  * - The inside out twin of collideSphereBox, for keeping things in a room or an arena
@@ -7427,14 +7610,17 @@ declare module "littlejsengine" {
7427
7610
  /**
7428
7611
  * Returns the vector to move box A by so it no longer overlaps box B, the shortest way out, or undefined
7429
7612
  * - The 3D twin of collideBoxBox
7613
+ * - Turned boxes are tested by the separating axis test, the push is along the direction they overlap least on
7430
7614
  * @param {Vector3} posA
7431
7615
  * @param {Vector3} sizeA - Full size of box A
7432
7616
  * @param {Vector3} posB
7433
7617
  * @param {Vector3} sizeB - Full size of box B
7618
+ * @param {Vector3} [rotationA] - How box A is turned, upright when left out
7619
+ * @param {Vector3} [rotationB] - How box B is turned
7434
7620
  * @return {Vector3|undefined}
7435
7621
  * @memberof Math3D
7436
7622
  */
7437
- export function collideBoxBox3D(posA: Vector3, sizeA: Vector3, posB: Vector3, sizeB: Vector3): Vector3 | undefined;
7623
+ export function collideBoxBox3D(posA: Vector3, sizeA: Vector3, posB: Vector3, sizeB: Vector3, rotationA?: Vector3, rotationB?: Vector3): Vector3 | undefined;
7438
7624
  /**
7439
7625
  * Returns the distance along the ray to the first intersection with a sphere, or undefined
7440
7626
  * - The hit is ray.getPosition(distance), a direction that is not unit length scales the distance
@@ -7457,16 +7643,17 @@ declare module "littlejsengine" {
7457
7643
  */
7458
7644
  export function raycastPlane(ray: Ray3D, planePos: Vector3, planeNormal: Vector3): number | undefined;
7459
7645
  /**
7460
- * Returns the distance along the ray to the first intersection with an axis aligned box, or undefined
7646
+ * Returns the distance along the ray to the first intersection with a box, or undefined
7461
7647
  * - The hit is ray.getPosition(distance), a direction that is not unit length scales the distance
7462
7648
  * - A ray starting inside the box is already there, so it gets back 0
7463
7649
  * @param {Ray3D} ray
7464
7650
  * @param {Vector3} pos - Center of the box
7465
7651
  * @param {Vector3} size - Full size of the box
7652
+ * @param {Vector3} [rotation] - How the box is turned, upright when left out
7466
7653
  * @return {number|undefined}
7467
7654
  * @memberof Math3D
7468
7655
  */
7469
- export function raycastBox(ray: Ray3D, pos: Vector3, size: Vector3): number | undefined;
7656
+ export function raycastBox(ray: Ray3D, pos: Vector3, size: Vector3, rotation?: Vector3): number | undefined;
7470
7657
  /**
7471
7658
  * LittleJS 3D Rendering Plugin
7472
7659
  * - Adds a 3D scene that draws into the same WebGL canvas as the 2D game
@@ -7531,6 +7718,10 @@ declare module "littlejsengine" {
7531
7718
  /** @property {boolean} - Default for every builder's smooth argument: true for smooth vertex normals, false for
7532
7719
  * flat faces */
7533
7720
  smoothShading: boolean;
7721
+ /** @property {boolean} - Draw the camera's depth into a texture each frame for post processing:
7722
+ * PostProcessPlugin hands it to its shader as iChannel2, read with sceneDepth(uv); off by default and free
7723
+ * when off, on it draws the solid objects of the default layer once more, depth only */
7724
+ depthTexture: boolean;
7534
7725
  /** @property {boolean} - Cast real shadows from the sun, off by default and free when off */
7535
7726
  shadows: boolean;
7536
7727
  /** @property {number} - Size of the shadow map in pixels, bigger is sharper and slower */
@@ -7562,8 +7753,23 @@ declare module "littlejsengine" {
7562
7753
  cullBackFaces: boolean;
7563
7754
  mirrored: boolean;
7564
7755
  /** @property {number} - Strength of the highlight where the sun and the Light3D objects reflect, 0 is none and
7565
- * 1 adds a light's full color at its brightest; its size is fixed */
7756
+ * 1 adds a light's full color at its brightest; shininess sets its size */
7566
7757
  specular: number;
7758
+ /** @property {number} - The highlight's exponent, how small and sharp it is: 4 is broad like rubber, 100 sharp
7759
+ * like polished metal; set from each object's shininess */
7760
+ shininess: number;
7761
+ /** @property {TextureInfo|undefined} - Normal map for the next draws, set from each object's normalMap
7762
+ * @type {TextureInfo|undefined} */
7763
+ normalMap: TextureInfo | undefined;
7764
+ /** @property {number} - How strongly the normal map bends the surface, set from each object's normalScale */
7765
+ normalScale: number;
7766
+ /** @property {number} - How much the surface reflects the sky, 0 to 1, set from each object's reflectivity */
7767
+ reflectivity: number;
7768
+ /** @property {TextureInfo|undefined} - Emissive map for the next draws, set from each object's emissiveMap
7769
+ * @type {TextureInfo|undefined} */
7770
+ emissiveMap: TextureInfo | undefined;
7771
+ /** @property {Color} - Multiplies the emissive map, set from each object's emissiveMapColor */
7772
+ emissiveMapColor: Color;
7567
7773
  /** @property {Shader|undefined} - Custom Shader for the next draws, set from each object's shader; undefined
7568
7774
  * draws with the plugin's own
7569
7775
  * @type {Shader|undefined} */
@@ -7654,6 +7860,13 @@ declare module "littlejsengine" {
7654
7860
  /** @type {WebGLFramebuffer|undefined} */
7655
7861
  shadowFramebuffer: WebGLFramebuffer | undefined;
7656
7862
  shadowTextureSize: number;
7863
+ /** @type {WebGLTexture|undefined} */
7864
+ cameraDepthTexture: WebGLTexture | undefined;
7865
+ /** @type {WebGLFramebuffer|undefined} */
7866
+ cameraDepthFramebuffer: WebGLFramebuffer | undefined;
7867
+ cameraDepthWidth: number;
7868
+ cameraDepthHeight: number;
7869
+ depthPass: boolean;
7657
7870
  contextGeneration: number;
7658
7871
  uniforms: Map<any, any>;
7659
7872
  /** @type {Object<string, Array<number>>} */
@@ -7953,17 +8166,17 @@ declare module "littlejsengine" {
7953
8166
  * EngineObject3D - An EngineObject with a 3D transform and a mesh
7954
8167
  * - Set pos3D, rotation3D and scale3D instead of the 2D pos, size and angle
7955
8168
  * - Gets update, children, timers, destroy and renderOrder from EngineObject
7956
- * - velocity3D is added to pos3D each frame, along with render3D.gravity and damping once it has a mass
8169
+ * - velocity3D is added to pos3D each frame, slowed by damping, and render3D.gravity pulls it once it has a mass
7957
8170
  * - Objects face -Z, the same way the camera does, so lookAt turns them to face a point
7958
8171
  * - The 2D pos and velocity are still there but nothing draws them
7959
- * - These inherited fields are 2D only and do nothing here: angle, angleVelocity, angleDamping,
7960
- * additiveColor, drawSize, mirror, clampSpeed, friction and groundObject
8172
+ * - These inherited fields are 2D only and do nothing here: angle, angleVelocity, additiveColor, drawSize and mirror;
8173
+ * damping, angleDamping, clampSpeed, friction and groundObject work as in 2D, on velocity3D and angleVelocity3D
7961
8174
  * - The inherited shader works here as in 2D, and with emissive at 1 its snippet does its own lighting
7962
8175
  * - Set sync2D for a 2D game with 3D looks, pos and angle then drive pos3D and rotation3D,
7963
8176
  * which is the one way those 2D fields reach a 3D object
7964
8177
  * - setCollision takes the same flags as in 2D, but the solid collision happens in 3D against size3D
7965
- * - The solid box is axis aligned in the world, rotation3D is ignored like angle is in 2D, so give a turned wall a
7966
- * size3D along the world axes
8178
+ * - The solid box turns with rotation3D, so a turned wall or a ramp collides as it looks; resting on one no steeper
8179
+ * than groundAngle stands there
7967
8180
  * - Its tile and raycast halves are 2D only so they default off here, and a child sits solid collision out
7968
8181
  * - A sync2D object collides in 2D instead, which needs the 2D size set as well as size3D
7969
8182
  * - setMesh swaps the mesh and frees the old one, for text and terrain that get built again
@@ -7997,7 +8210,7 @@ declare module "littlejsengine" {
7997
8210
  /** @property {Vector3} - Added to pos3D each frame by the engine before update, like the 2D velocity, no super
7998
8211
  * call needed; damping and render3D.gravity act on it once the object has a mass */
7999
8212
  velocity3D: Vector3;
8000
- /** @property {Vector3} - Added to rotation3D each frame by the engine before update, angleDamping is 2D only */
8213
+ /** @property {Vector3} - Added to rotation3D each frame by the engine before update, slowed by angleDamping */
8001
8214
  angleVelocity3D: Vector3;
8002
8215
  /** @property {Mesh|undefined} - Mesh to draw
8003
8216
  * @type {Mesh|undefined} */
@@ -8019,11 +8232,33 @@ declare module "littlejsengine" {
8019
8232
  /** @property {boolean} - Additive blending, in the transparent stage */
8020
8233
  additive: boolean;
8021
8234
  /** @property {number} - Strength of the highlight where the sun and the Light3D objects reflect, 0 is none and
8022
- * 1 adds a light's full color at its brightest; its size is fixed */
8235
+ * 1 adds a light's full color at its brightest; shininess sets its size */
8023
8236
  specular: number;
8237
+ /** @property {number} - The highlight's exponent, how small and sharp it is: 4 is broad like rubber, 16 the
8238
+ * default, 100 sharp like polished metal; shows only with specular above 0 */
8239
+ shininess: number;
8240
+ /** @property {TextureInfo|undefined} - A normal map that bends the surface at each texel so it catches the
8241
+ * light like bumps and grooves, green pointing up the image as OpenGL and glTF have it; read at the color
8242
+ * texture's coordinates, see normalMapFromHeight to make one in code
8243
+ * @type {TextureInfo|undefined} */
8244
+ normalMap: TextureInfo | undefined;
8245
+ /** @property {number} - How strongly the normal map bends the surface, 0 turns it off, as glTF's scale */
8246
+ normalScale: number;
8247
+ /** @property {number} - How much it reflects the sky, 0 none and 1 a mirror of it; the edges seen at a
8248
+ * glancing angle reflect more either way, as water and glass do */
8249
+ reflectivity: number;
8250
+ /** @property {TextureInfo|undefined} - A texture of where it glows, added on top of the lit surface so it
8251
+ * shows in the dark, like lit windows; read at the color texture's coordinates
8252
+ * @type {TextureInfo|undefined} */
8253
+ emissiveMap: TextureInfo | undefined;
8254
+ /** @property {Color} - Multiplies the emissive map, as glTF's emissiveFactor */
8255
+ emissiveMapColor: Color;
8024
8256
  /** @property {boolean} - Collide as the sphere that fits size3D instead of as the size3D box, so it rolls
8025
8257
  * around corners */
8026
8258
  collideAsSphere3D: boolean;
8259
+ /** @property {number} - The steepest slope it stands on, in radians from level, PI/4 by default: resting on
8260
+ * a solid within this of flat sets groundObject and holds it still, steeper it slides down */
8261
+ groundAngle: number;
8027
8262
  /** @property {boolean} - Darkened by the shadow map when render3D.shadows is on */
8028
8263
  receiveShadow: boolean;
8029
8264
  /** @property {boolean|undefined} - Draw this object over the 2D scene, undefined uses render3D.renderAfter2D
@@ -8499,6 +8734,15 @@ declare module "littlejsengine" {
8499
8734
  * @memberof Render3D
8500
8735
  */
8501
8736
  export function buildSky(topColor?: Color, horizonColor?: Color, bottomColor?: Color, sides?: number, rings?: number): Mesh;
8737
+ /** Make a normal map from a height at each pixel, for bumps and grooves with no image file: the slope at each pixel
8738
+ * from its neighbors' heights, taken around the edges so the map tiles; set it as an object's normalMap
8739
+ * @param {Vector2} size - In pixels
8740
+ * @param {function(number, number): number} heightFunction - The height 0 to 1 at a pixel, x across and y down
8741
+ * @param {number} [strength] - How steep the slopes are: a height change of 1 over one pixel leans the normal
8742
+ * by strength
8743
+ * @return {TextureInfo} - Wraps; headless it has no image
8744
+ * @memberof Render3D */
8745
+ export function normalMapFromHeight(size: Vector2, heightFunction: (arg0: number, arg1: number) => number, strength?: number): TextureInfo;
8502
8746
  /**
8503
8747
  * Turn a sprite into a 3D block model by giving its pixels thickness
8504
8748
  * - A pixel counts as solid when it is more than half opaque
@@ -8607,6 +8851,16 @@ declare module "littlejsengine" {
8607
8851
  * @return {number|undefined}
8608
8852
  * @ignore */
8609
8853
  levelRaycast3D(ray: Ray3D): number | undefined;
8854
+ /** Where a short move goes under the surface, for a particle's move in one frame: the part of the move made
8855
+ * before it, 0 to 1, and the surface normal there; undefined when it stays above, starts under, or is off the map
8856
+ * @param {Vector3} from
8857
+ * @param {Vector3} to
8858
+ * @return {{distance: number, normal: Vector3}|undefined}
8859
+ * @ignore */
8860
+ levelSegment3D(from: Vector3, to: Vector3): {
8861
+ distance: number;
8862
+ normal: Vector3;
8863
+ };
8610
8864
  /** Keep an object above the ground, called by the engine for each object with collideLevel
8611
8865
  * @param {EngineObject3D} o
8612
8866
  * @param {Vector3} oldPos - Where it was before it moved
@@ -8752,6 +9006,16 @@ declare module "littlejsengine" {
8752
9006
  * @return {number|undefined}
8753
9007
  * @ignore */
8754
9008
  levelRaycast3D(ray: Ray3D): number | undefined;
9009
+ /** Where a short move goes into a block, for a particle's move in one frame: the part of the move made before it,
9010
+ * 0 to 1, and the normal of the face it comes in through; undefined when it hits none, or starts inside one
9011
+ * @param {Vector3} from
9012
+ * @param {Vector3} to
9013
+ * @return {{distance: number, normal: Vector3}|undefined}
9014
+ * @ignore */
9015
+ levelSegment3D(from: Vector3, to: Vector3): {
9016
+ distance: number;
9017
+ normal: Vector3;
9018
+ } | undefined;
8755
9019
  /** Draw the chunks, each at its center, with the whole texture so each face shows its own tile
8756
9020
  * @param {boolean} transparent
8757
9021
  * @ignore */
@@ -8786,6 +9050,12 @@ declare module "littlejsengine" {
8786
9050
  /** @property {boolean} - Shine from far away, from its position toward the origin, instead of out from its
8787
9051
  * position with a falloff; DirectionalLight3D sets it */
8788
9052
  directional: boolean;
9053
+ /** @property {number} - Size of a soft hazy glow drawn over the light, like a lamp at night, 0 for none; it
9054
+ * is added onto what is behind it, and what is in front of the light hides it */
9055
+ glow: number;
9056
+ /** @property {number} - How fast the glow fades from its middle: 1 by default, .5 a wide haze, 2 a tight
9057
+ * bright core */
9058
+ glowFalloff: number;
8789
9059
  }
8790
9060
  /**
8791
9061
  * DirectionalLight3D - A Light3D that shines from far away with no falloff, like sunlight
@@ -8881,13 +9151,39 @@ declare module "littlejsengine" {
8881
9151
  /** @property {boolean} - Capture the mouse on a click, so looking needs no button held */
8882
9152
  lockPointer: boolean;
8883
9153
  /** @property {number} - Speed of a jump in world units a frame, 0 for none; Space or gamepad button 0 jumps
8884
- * while it stands on something, a height map or voxel map it collides with, see collideLevel */
9154
+ * while it stands on something, a height map, a voxel map or a solid, see groundObject */
8885
9155
  jumpSpeed: number;
8886
9156
  /** @property {number} - How far above its position the eye is, in its own space, so with a size3D the eye can
8887
9157
  * sit toward the top of the body instead of its middle; keep it under half the body's height, or the eye is
8888
9158
  * outside the body and sees through a ceiling it stands under */
8889
9159
  eyeHeight: number;
8890
9160
  }
9161
+ /**
9162
+ * A particle as a ParticleEmitter3D's callbacks see it: one object the emitter reuses, set from the particle for each
9163
+ * call and written back after it, so copy what you keep
9164
+ * @typedef {Object} Particle3D
9165
+ * @property {ParticleEmitter3D} emitter - The emitter it is in
9166
+ * @property {Vector3} pos - Where it is, change it to move it
9167
+ * @property {Vector3} velocity - How far it moves each frame
9168
+ * @property {number} age - Seconds it has lived
9169
+ * @property {number} lifeTime - Seconds it lives
9170
+ * @property {boolean} destroyed - Set by destroy
9171
+ * @property {function(): void} destroy - End it this update, the destroy callback gets it
9172
+ * @memberof Render3D
9173
+ */
9174
+ /**
9175
+ * @callback Particle3DCallback - A function a ParticleEmitter3D calls with one of its particles
9176
+ * @param {Particle3D} particle
9177
+ * @memberof Render3D
9178
+ */
9179
+ /**
9180
+ * @callback Particle3DCollideCallback - Decides whether a particle stops where it hits the level, a filter as in 2D
9181
+ * @param {Particle3D} particle
9182
+ * @param {EngineObject3D} level - The HeightMap or VoxelMap it hit
9183
+ * @param {Vector3} pos - Where it hit
9184
+ * @return {boolean|void} - true to stop it there; a callback that returns nothing lets it pass through
9185
+ * @memberof Render3D
9186
+ */
8891
9187
  /**
8892
9188
  * ParticleEmitter3D - Spawns camera facing particles, the 3D twin of ParticleEmitter
8893
9189
  * - Each particle is a flat square facing the camera, with a soft round dot when no tile is given
@@ -8900,6 +9196,10 @@ declare module "littlejsengine" {
8900
9196
  * - gravity here is its own number added to velocity y each frame: it is neither the engine's 2D
8901
9197
  * gravity nor render3D.gravity, so an effect keeps its own fall wherever it is used
8902
9198
  * - An emitter with an emitTime destroys itself once its last particle is gone, like the 2D emitter
9199
+ * - Callbacks as the 2D emitter's: particleCreateCallback, particleUpdateCallback, particleCollideCallback and
9200
+ * particleDestroyCallback, each given a Particle3D, one object the emitter reuses for every particle and call
9201
+ * - collideLevel, off by default, has particles hit the height maps and voxel maps, bouncing by restitution and
9202
+ * sliding by friction
8903
9203
  * @extends EngineObject3D
8904
9204
  * @memberof Render3D
8905
9205
  * @example
@@ -8959,7 +9259,8 @@ declare module "littlejsengine" {
8959
9259
  fadeRate: number;
8960
9260
  /** @property {number} - Extra randomness applied to speed, size and life */
8961
9261
  randomness: number;
8962
- /** @property {number} - Seconds of each particle's path to draw as a ribbon behind it, 0 draws billboards */
9262
+ /** @property {number} - Seconds of each particle's path to draw as a ribbon behind it, 0 draws billboards;
9263
+ * with engineVariableStep it keeps trailTime * frameRate updates of path */
8963
9264
  trailTime: number;
8964
9265
  /** @property {number} - Radians per frame each particle turns in the camera plane, either way; 0 is no spin */
8965
9266
  angleSpeed: number;
@@ -8973,12 +9274,30 @@ declare module "littlejsengine" {
8973
9274
  trailData: Float32Array | undefined;
8974
9275
  /** @property {number} - Trail points kept per particle, from trailTime */
8975
9276
  trailMax: number;
9277
+ /** @property {Particle3DCallback|undefined} - Called with each particle as it is made
9278
+ * @type {Particle3DCallback|undefined} */
9279
+ particleCreateCallback: Particle3DCallback | undefined;
9280
+ /** @property {Particle3DCallback|undefined} - Called with each particle each update, after it moves
9281
+ * @type {Particle3DCallback|undefined} */
9282
+ particleUpdateCallback: Particle3DCallback | undefined;
9283
+ /** @property {Particle3DCollideCallback|undefined} - Decides if a particle stops where it hits the level,
9284
+ * with collideLevel on; a callback that returns nothing lets it through
9285
+ * @type {Particle3DCollideCallback|undefined} */
9286
+ particleCollideCallback: Particle3DCollideCallback | undefined;
9287
+ /** @property {Particle3DCallback|undefined} - Called with each particle as it goes, its life over or destroyed
9288
+ * @type {Particle3DCallback|undefined} */
9289
+ particleDestroyCallback: Particle3DCallback | undefined;
9290
+ /** @property {Particle3D} - The particle the callbacks get, one object for every particle and call
9291
+ * @type {Particle3D} */
9292
+ particleView: Particle3D;
8976
9293
  /** @property {Vector3|undefined} - Where the emitter was at its last update, for when its parent is destroyed
8977
9294
  * @type {Vector3|undefined} */
8978
9295
  worldPos3D: Vector3 | undefined;
8979
9296
  emitTimeBuffer: number;
8980
9297
  /** Spawn one particle now */
8981
9298
  emitParticle(): void;
9299
+ particleCall(callback: any, k: any, level: any, pos: any): any;
9300
+ particleCollide(k: any, x: any, y: any, z: any): void;
8982
9301
  }
8983
9302
  /**
8984
9303
  * Trail3D - A ribbon through where the object has been, thinning and fading with age
@@ -9025,8 +9344,8 @@ declare module "littlejsengine" {
9025
9344
  }
9026
9345
  /**
9027
9346
  * Collect the EngineObject3D objects whose boxes overlap a sphere or a box, the 3D twin of engineObjectsCollect
9028
- * - Boxes are axis aligned around the world position, rotation3D is ignored; lights, emitters and trails have no size
9029
- * and are never collected
9347
+ * - Each object is its size3D box at its world position, turned as it is turned; lights, emitters and trails have no
9348
+ * size and are never collected
9030
9349
  * @param {Vector3} pos - Center of the area
9031
9350
  * @param {Vector3|number} size - Diameter of a sphere if a number, 0 for a point, full size of a box if a Vector3
9032
9351
  * @param {Array<EngineObject>} [objects] - Defaults to every object
@@ -9154,6 +9473,8 @@ declare module "littlejsengine" {
9154
9473
  * GLTFObject that createObject makes; a skinned character's walk is not read
9155
9474
  * - Materials give a base color and texture and whether they blend; glass made with KHR_materials_transmission blends too,
9156
9475
  * and a KHR_materials_unlit material comes in emissive, its own color with no shading
9476
+ * - A material's normal map and emissive map load too, with its normal scale and emissive factor, read at the base
9477
+ * color texture's uvs; roughness, metalness and occlusion maps are not loaded
9157
9478
  * - The base color texture reads the uv set its texCoord names, moved by KHR_texture_transform as gltfpack and
9158
9479
  * Blender write it
9159
9480
  * - An OPAQUE material, the default, ignores its texture's alpha as the format says: a texture only such materials
@@ -9196,6 +9517,17 @@ declare module "littlejsengine" {
9196
9517
  /** @property {boolean} - The material is unlit (KHR_materials_unlit), its own color with no shading; the object
9197
9518
  * createObject makes draws it with emissive 1 */
9198
9519
  unlit: boolean;
9520
+ /** @property {TextureInfo|undefined} - The material's normal map, drawn with the base color texture's uvs
9521
+ * @type {TextureInfo|undefined} */
9522
+ normalMap: TextureInfo | undefined;
9523
+ /** @property {number} - The normal map's strength, its scale in the file */
9524
+ normalScale: number;
9525
+ /** @property {TextureInfo|undefined} - The material's emissive map, or a white texture when it has an
9526
+ * emissiveFactor and no texture, so it glows all over
9527
+ * @type {TextureInfo|undefined} */
9528
+ emissiveMap: TextureInfo | undefined;
9529
+ /** @property {Color} - The emissiveFactor, which multiplies the emissive map */
9530
+ emissiveMapColor: Color;
9199
9531
  }
9200
9532
  /**
9201
9533
  * GLTFObject - A model as an object with a child per part, which plays the model's animations
@@ -9301,6 +9633,48 @@ declare module "littlejsengine" {
9301
9633
  * @param {number} [size] - Length of the cross
9302
9634
  * @memberof Render3D */
9303
9635
  export function debugPoint3D(pos: Vector3, color?: Color, time?: number, size?: number): void;
9636
+ /** Add a type of object, so level3DLoad makes one wherever a level has an object of that type
9637
+ * - The name is a string because minified builds rename classes
9638
+ * - A class, or any function with a prototype, is made with new make(pos3D, properties); an arrow function is
9639
+ * called as make(pos3D, properties), for what is not an object, like a player start
9640
+ * - properties is the defaults with the object's own values over them, and each of the type's own is also set on
9641
+ * what was made; a property the type has no default for is in properties and is not set
9642
+ * - Give a class a constructor of its own that takes the position: one that hands every argument on to
9643
+ * EngineObject3D would hand it the properties as its mesh
9644
+ * - An EngineObject3D then gets the object's rotation, and its scale times the scale it was made with
9645
+ * - Adding a name again replaces it, Box, Sphere, Cylinder and Light too
9646
+ * @param {string} name - The type the objects have in the level
9647
+ * @param {Function} make - A class made at each object's position, or a function called with it
9648
+ * @param {Object} [defaults] - Properties of each one made, the level editor shows inputs for them
9649
+ * @param {TileInfo} [tileInfo] - An icon for the level editor
9650
+ * @memberof Level3D
9651
+ * @example
9652
+ * level3DAddType('Crate', Crate, {health: 3});
9653
+ * level3DAddType('PlayerStart', (pos)=> playerStart = pos); */
9654
+ export function level3DAddType(name: string, make: Function, defaults?: any, tileInfo?: TileInfo): void;
9655
+ /** Add a type that is a mesh and nothing more, a static prop with no class to write, for a built mesh or a model
9656
+ * - Each object has a color and a solid property, solid collides as the box around the mesh
9657
+ * @param {string} name - The type the objects have in the level
9658
+ * @param {Mesh} mesh - Shared by every object of the type
9659
+ * @param {TileInfo} [tileInfo] - Its texture
9660
+ * @param {Color} [color] - Its color, an object's own color property goes over it
9661
+ * @memberof Level3D
9662
+ * @example
9663
+ * level3DAddMesh('Tree', treeMesh, tile(4)); */
9664
+ export function level3DAddMesh(name: string, mesh: Mesh, tileInfo?: TileInfo, color?: Color): void;
9665
+ /** Make the objects of a level, each from the type added for its name
9666
+ * - The level is an object: {littlejs3D: 1, objects: [{id, type, pos: [x, y, z]}, ...]}, and {} is a new one
9667
+ * - rotation is pitch, yaw and roll in degrees, scale is a number for each axis, both left out when they are
9668
+ * the default, and properties holds what differs from the type's defaults
9669
+ * - A Color property is a #rrggbb or #rrggbbaa string, a Vector2 or Vector3 an array, as the default says
9670
+ * - An object whose type was not added is skipped, with a warning in debug builds
9671
+ * - What a file written by hand gets wrong uses the default: a value that is not of its default's type
9672
+ * - An object its type can not make is skipped with an error in debug builds, where asserts throw, and the rest
9673
+ * of the level is made
9674
+ * @param {Object} level - The level, the level editor edits this same object
9675
+ * @return {Array<any>} - What each object's type made, a function that made nothing is left out
9676
+ * @memberof Level3D */
9677
+ export function level3DLoad(level: any): Array<any>;
9304
9678
  /**
9305
9679
  * LittleJS Three.js Plugin
9306
9680
  * - Renders a three.js scene on a canvas behind the LittleJS canvases
@@ -9548,6 +9922,14 @@ declare module "littlejsengine" {
9548
9922
  * section has Play from mouse, which starts play there, Escape at the mouse and Play at the view center
9549
9923
  * @type {EditorPlayFromCallback|undefined} */
9550
9924
  onPlayFrom: EditorPlayFromCallback | undefined;
9925
+ /** @property {Array<number>|undefined} - The tiles the palette shows, in its order, for a sheet that also holds
9926
+ * sprites and art that are not level tiles; undefined shows every tile of the sheet
9927
+ * @type {Array<number>|undefined} */
9928
+ paletteTiles: Array<number> | undefined;
9929
+ /** @property {boolean|undefined} - Which level editor opens: true the 3D one, false the 2D one, undefined the
9930
+ * 3D one when a level was loaded with level3DLoad and there is a Render3DPlugin
9931
+ * @type {boolean|undefined} */
9932
+ use3D: boolean | undefined;
9551
9933
  /** True while the editor is open, the game is paused under it
9552
9934
  * @return {boolean} */
9553
9935
  get isOpen(): boolean;