littlejsengine 1.18.28 → 1.19.3

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.
@@ -23,6 +23,13 @@ declare module "littlejsengine" {
23
23
  * - A function that draws to a 2D canvas context
24
24
  */
25
25
  export type Canvas2DDrawFunction = (context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D) => any;
26
+ /**
27
+ * Anything with input and output audio nodes, like an effect from the audio effects plugin
28
+ */
29
+ export type AudioEffectNodes = {
30
+ input: AudioNode;
31
+ output: AudioNode;
32
+ };
26
33
  /**
27
34
  * - Function called when a sound ends
28
35
  */
@@ -163,6 +170,7 @@ declare module "littlejsengine" {
163
170
  export function engineObjectsUpdate(): void;
164
171
  /** Destroy and remove all objects
165
172
  * - This can be used to clear out all objects when restarting a level
173
+ * - Objects with the persistent flag set are left alone, for things that outlive a level
166
174
  * - Objects can override their destroy function to do cleanup or stick around
167
175
  * @param {boolean} [immediate] - should attached effects be allowed to die off?
168
176
  * @memberof Engine */
@@ -202,8 +210,9 @@ declare module "littlejsengine" {
202
210
  * @param {PluginCallback} [render]
203
211
  * @param {PluginCallback} [glContextLost]
204
212
  * @param {PluginCallback} [glContextRestored]
213
+ * @param {PluginCallback} [preRender] - Called after the canvas is cleared and before gameRender
205
214
  * @memberof Engine */
206
- export function engineAddPlugin(update?: PluginCallback, render?: PluginCallback, glContextLost?: PluginCallback, glContextRestored?: PluginCallback): void;
215
+ export function engineAddPlugin(update?: PluginCallback, render?: PluginCallback, glContextLost?: PluginCallback, glContextRestored?: PluginCallback, preRender?: PluginCallback): void;
207
216
  /**
208
217
  * LittleJS Debug System
209
218
  * - Press Esc to toggle debug overlay with object picking
@@ -371,9 +380,10 @@ declare module "littlejsengine" {
371
380
  * @type {Color}
372
381
  * @memberof Settings */
373
382
  export let canvasClearColor: Color;
374
- /** The max size of the canvas, centered if window is larger
383
+ /** The max size of the canvas in css pixels, centered if window is larger
384
+ * - Not affected by canvasPixelRatio, the backing store may be larger than this
375
385
  * @type {Vector2}
376
- * @default Vector2(1920,1080)
386
+ * @default Vector2(3840,2160)
377
387
  * @memberof Settings */
378
388
  export let canvasMaxSize: Vector2;
379
389
  /** Minimum aspect ratio of the canvas (width/height), unused if 0
@@ -388,8 +398,9 @@ declare module "littlejsengine" {
388
398
  * @default
389
399
  * @memberof Settings */
390
400
  export let canvasMaxAspect: number;
391
- /** Fixed size of the canvas, if enabled canvas size never changes
401
+ /** Fixed size of the canvas in css pixels, if enabled canvas size never changes
392
402
  * - you may also need to set mainCanvasSize if using screen space coords in startup
403
+ * - canvasPixelRatio still applies, it only scales the backing store
393
404
  * @type {Vector2}
394
405
  * @default Vector2()
395
406
  * @memberof Settings */
@@ -407,8 +418,13 @@ declare module "littlejsengine" {
407
418
  * @default
408
419
  * @memberof Settings */
409
420
  export let tilesPixelated: boolean;
410
- /** Scale factor applied to the canvas backing store for native-resolution rendering.
421
+ /** Scale factor applied to the canvas resolution for sharper rendering
411
422
  * Pass 1 for no scaling, a number for an explicit ratio, or undefined to track devicePixelRatio each frame.
423
+ * - Only the backing store scales, so this changes sharpness and nothing else
424
+ * - mainCanvasSize, cameraScale, mousePos and screen space stay in css pixels,
425
+ * so the same code draws the same size at any ratio
426
+ * - Pixel art usually looks best left at 1 or set to whole numbers,
427
+ * a fractional ratio samples texels unevenly
412
428
  * @type {number|undefined}
413
429
  * @default
414
430
  * @memberof Settings */
@@ -645,6 +661,13 @@ declare module "littlejsengine" {
645
661
  * @default
646
662
  * @memberof Settings */
647
663
  export let soundDefaultTaper: number;
664
+ /** Pause all sound while the page is hidden, and pick up where it was when it shows again
665
+ * - A hidden page stops the game, so without this a looping sound plays on over a frozen game
666
+ * - Turn it off to keep music playing in a background tab
667
+ * @type {boolean}
668
+ * @default
669
+ * @memberof Settings */
670
+ export let soundPauseWhenHidden: boolean;
648
671
  /** Set position of camera in world space
649
672
  * @param {Vector2} pos
650
673
  * @memberof Settings */
@@ -697,11 +720,24 @@ declare module "littlejsengine" {
697
720
  * @param {boolean} pixelated
698
721
  * @memberof Settings */
699
722
  export function setTilesPixelated(pixelated: boolean): void;
700
- /** Set the canvas pixel ratio.
723
+ /** Set the canvas pixel ratio, scales the render resolution for sharper output
701
724
  * Pass a number for an explicit ratio, or call with no argument to track devicePixelRatio each frame.
725
+ * - The canvas stays the same size on screen and everything draws the same
726
+ * size, it just renders at a higher resolution so nothing looks blurry
727
+ * - Game code is unaffected, it always works in css pixels
702
728
  * @param {number} [pixelRatio]
729
+ * @example
730
+ * // render at native resolution, capped so phones don't pay for 3x
731
+ * setCanvasPixelRatio(min(devicePixelRatio, 2));
703
732
  * @memberof Settings */
704
733
  export function setCanvasPixelRatio(pixelRatio?: number): void;
734
+ /** Get the pixel ratio currently applied to the canvas backing store
735
+ * - Resolves canvasPixelRatio, falling back to devicePixelRatio when it is undefined
736
+ * - Game code works in css pixels so this is rarely needed, it is for sizing
737
+ * render targets and viewports that must match the backing store
738
+ * @return {number}
739
+ * @memberof Settings */
740
+ export function getCanvasPixelRatio(): number;
705
741
  /** Set default font used for text rendering
706
742
  * @param {string} font
707
743
  * @memberof Settings */
@@ -870,6 +906,10 @@ declare module "littlejsengine" {
870
906
  * @param {number} taper
871
907
  * @memberof Settings */
872
908
  export function setSoundDefaultTaper(taper: number): void;
909
+ /** Set if all sound pauses while the page is hidden
910
+ * @param {boolean} pause
911
+ * @memberof Settings */
912
+ export function setSoundPauseWhenHidden(pause: boolean): void;
873
913
  /** Set if watermark with FPS should be shown
874
914
  * @param {boolean} show
875
915
  * @memberof Debug */
@@ -1061,6 +1101,31 @@ declare module "littlejsengine" {
1061
1101
  * @return {boolean} - True if intersecting
1062
1102
  * @memberof Math */
1063
1103
  export function isIntersecting(start: Vector2, end: Vector2, pos: Vector2, size: Vector2): boolean;
1104
+ /** Returns the vector to move circle A by so it no longer overlaps circle B, or undefined
1105
+ * @param {Vector2} posA - Center of circle A
1106
+ * @param {number} radiusA
1107
+ * @param {Vector2} posB - Center of circle B
1108
+ * @param {number} radiusB
1109
+ * @return {Vector2|undefined}
1110
+ * @memberof Math */
1111
+ export function collideCircleCircle(posA: Vector2, radiusA: number, posB: Vector2, radiusB: number): Vector2 | undefined;
1112
+ /** Returns the vector to move a circle out of an axis aligned box, or undefined
1113
+ * @param {Vector2} pos - Center of the circle
1114
+ * @param {number} radius
1115
+ * @param {Vector2} boxPos - Center of the box
1116
+ * @param {Vector2} boxSize - Full size of the box
1117
+ * @return {Vector2|undefined}
1118
+ * @memberof Math */
1119
+ export function collideCircleBox(pos: Vector2, radius: number, boxPos: Vector2, boxSize: Vector2): Vector2 | undefined;
1120
+ /** Returns the vector to move box A by so it no longer overlaps box B, the shortest way out, or undefined
1121
+ * - isOverlapping is the yes or no version of this
1122
+ * @param {Vector2} posA - Center of box A
1123
+ * @param {Vector2} sizeA - Full size of box A
1124
+ * @param {Vector2} posB - Center of box B
1125
+ * @param {Vector2} sizeB - Full size of box B
1126
+ * @return {Vector2|undefined}
1127
+ * @memberof Math */
1128
+ export function collideBoxBox(posA: Vector2, sizeA: Vector2, posB: Vector2, sizeB: Vector2): Vector2 | undefined;
1064
1129
  /**
1065
1130
  * @callback LineTestFunction - Checks if a position is colliding
1066
1131
  * @param {Vector2} pos
@@ -1100,6 +1165,14 @@ declare module "littlejsengine" {
1100
1165
  * @param {string} [type]
1101
1166
  * @memberof Utilities */
1102
1167
  export function saveText(text: string, filename?: string, type?: string): void;
1168
+ /** Create an offscreen canvas to draw into, and return its 2D context
1169
+ * - The canvas is context.canvas, which is what TextureInfo and the like take
1170
+ * @param {number} width - In pixels
1171
+ * @param {number} [height] - In pixels, defaults to the width for a square
1172
+ * @param {boolean} [willReadFrequently] - Keep it in software, faster when getImageData is called on it often
1173
+ * @return {OffscreenCanvasRenderingContext2D}
1174
+ * @memberof Utilities */
1175
+ export function createCanvasContext(width: number, height?: number, willReadFrequently?: boolean): OffscreenCanvasRenderingContext2D;
1103
1176
  /** Save a canvas to disk
1104
1177
  * @param {HTMLCanvasElement|OffscreenCanvas} canvas
1105
1178
  * @param {string} [filename]
@@ -1310,6 +1383,7 @@ declare module "littlejsengine" {
1310
1383
  * @return {number} */
1311
1384
  distanceSquared(v: Vector2): number;
1312
1385
  /** Returns a new vector in same direction as this one with the length passed in
1386
+ * - A zero vector has no direction, so it normalizes to straight up
1313
1387
  * @param {number} [length]
1314
1388
  * @return {Vector2} */
1315
1389
  normalize(length?: number): Vector2;
@@ -1764,8 +1838,9 @@ declare module "littlejsengine" {
1764
1838
  size: Vector2;
1765
1839
  /** @property {Vector2} - inverse of the size, cached for rendering */
1766
1840
  sizeInverse: Vector2;
1767
- /** @property {WebGLTexture} - WebGL texture */
1768
- glTexture: any;
1841
+ /** @property {WebGLTexture|undefined} - WebGL texture
1842
+ * @type {WebGLTexture|undefined} */
1843
+ glTexture: WebGLTexture | undefined;
1769
1844
  /** @property {boolean} - true for REPEAT wrap mode, false for CLAMP_TO_EDGE */
1770
1845
  wrap: boolean;
1771
1846
  /** Creates the WebGL texture, updates if already created */
@@ -1779,6 +1854,105 @@ declare module "littlejsengine" {
1779
1854
  * @param {boolean} [wrap] - true for REPEAT, false for CLAMP_TO_EDGE */
1780
1855
  setWrap(wrap?: boolean): void;
1781
1856
  }
1857
+ /**
1858
+ * SpriteAnimation - Steps a tile through its frames over time: looping, once, or there and back
1859
+ * - Driven by the engine time like a Timer, so it pauses with the game and needs no update call
1860
+ * - Read tileInfo each frame for the frame to draw, from an object's update or before a drawTile
1861
+ * - loop, play and pingPong each start over from the first frame; stop holds the current one
1862
+ * - Frames follow each other along the row, as tileInfo.frame counts them
1863
+ * @example
1864
+ * const walk = new SpriteAnimation(tile(0, 16), 4, .1); // four frames, a tenth of a second each
1865
+ * const attack = new SpriteAnimation(tile(4, 16), 3, .05).play(); // once, then holds the last frame
1866
+ * // in update: this.tileInfo = (attack.isDone ? walk : attack).tileInfo;
1867
+ * @memberof Draw
1868
+ */
1869
+ export class SpriteAnimation {
1870
+ /** Create an animation over a run of frames, looping from the start
1871
+ * @param {TileInfo} tileInfo - The first frame
1872
+ * @param {number} frameCount - How many frames, one or more
1873
+ * @param {number} [frameTime] - Seconds each frame shows for */
1874
+ constructor(tileInfo: TileInfo, frameCount: number, frameTime?: number);
1875
+ /** @property {TileInfo} - The first frame, the others follow it along the row */
1876
+ firstTile: TileInfo;
1877
+ /** @property {number} - How many frames */
1878
+ frameCount: number;
1879
+ /** @property {number} - Seconds each frame shows for */
1880
+ frameTime: number;
1881
+ /** @property {number} - Rate multiplier, 2 plays twice as fast; set it before starting */
1882
+ speed: number;
1883
+ /** @property {string} - How it runs: 'loop', 'once' or 'pingPong', set by loop, play and pingPong */
1884
+ mode: string;
1885
+ /** @property {number} - Engine time it started at */
1886
+ startTime: number;
1887
+ /** @property {number|undefined} - The frame held by stop, undefined while running
1888
+ * @type {number|undefined} */
1889
+ heldFrame: number | undefined;
1890
+ /** Start over from the first frame and repeat forever
1891
+ * @return {SpriteAnimation} */
1892
+ loop(): SpriteAnimation;
1893
+ /** Start over from the first frame, run through once and hold the last frame
1894
+ * @return {SpriteAnimation} */
1895
+ play(): SpriteAnimation;
1896
+ /** Start over from the first frame and run there and back forever
1897
+ * @return {SpriteAnimation} */
1898
+ pingPong(): SpriteAnimation;
1899
+ /** Hold the current frame
1900
+ * @return {SpriteAnimation} */
1901
+ stop(): SpriteAnimation;
1902
+ /** Start over from the first frame in a mode
1903
+ * @param {string} [mode] - 'loop', 'once' or 'pingPong', the current mode when left out
1904
+ * @return {SpriteAnimation} */
1905
+ restart(mode?: string): SpriteAnimation;
1906
+ /** How many frames have gone by since the start, fractional
1907
+ * @return {number} */
1908
+ get elapsedFrames(): number;
1909
+ /** The frame showing now, 0 to frameCount-1
1910
+ * @return {number} */
1911
+ get frame(): number;
1912
+ /** The tile of the frame showing now
1913
+ * @return {TileInfo} */
1914
+ get tileInfo(): TileInfo;
1915
+ /** True once a play has shown its last frame for its time
1916
+ * @return {boolean} */
1917
+ get isDone(): boolean;
1918
+ }
1919
+ /**
1920
+ * Shader - A custom fragment shader for objects and draws, 2D or 3D
1921
+ * - Write a mainImage function in the post processing style, the renderer wraps it with its own program
1922
+ * - It gives the surface color, then the object's color and additive color apply in 2D, and the lighting,
1923
+ * shadows and fog in 3D; set emissive to 1 on a 3D object for the snippet's color to be final
1924
+ * - Set it as obj.shader, or use setShader for 2D draws and render3D.shader for 3D draws
1925
+ * - Draws that share a Shader share a batch; with no Shader set nothing changes
1926
+ * - In 2D it shades textured draws, untextured ones like drawRect draw as they are
1927
+ * - Compiled once per renderer by the first draw that needs it; a bad snippet throws with the GLSL log in debug
1928
+ * - Make each Shader once, at init, and share it; every one made lives for the session with its programs
1929
+ * - Names in both renderers: iChannel0 the texture, iTime, iResolution, and localUV, 0 to 1 across the sprite
1930
+ * or the mesh's own uv
1931
+ * - Names in 3D only: worldPos, worldNormal, cameraPos, sunDirection, sunColor, ambientColor, lightCount,
1932
+ * lights[i], lightColors[i] and shadow()
1933
+ * @example
1934
+ * const fade = new Shader(`
1935
+ * void mainImage(out vec4 c, vec2 uv)
1936
+ * {
1937
+ * c = texture(iChannel0, uv);
1938
+ * c.a *= .5 + .5*sin(iTime);
1939
+ * }`);
1940
+ * obj.shader = fade;
1941
+ * @memberof Draw
1942
+ */
1943
+ export class Shader {
1944
+ /** Create a shader from a fragment snippet that defines void mainImage(out vec4 c, vec2 uv)
1945
+ * @param {string} fragmentCode */
1946
+ constructor(fragmentCode: string);
1947
+ /** @property {string} - The mainImage snippet */
1948
+ fragmentCode: string;
1949
+ /** @property {WebGLProgram|undefined} - The 2D program, compiled by the first draw that needs it, read only
1950
+ * @type {WebGLProgram|undefined} */
1951
+ program: WebGLProgram | undefined;
1952
+ /** @property {WebGLProgram|undefined} - The 3D program, compiled by the 3D plugin the same way, read only
1953
+ * @type {WebGLProgram|undefined} */
1954
+ program3D: WebGLProgram | undefined;
1955
+ }
1782
1956
  /**
1783
1957
  * LittleJS Drawing System
1784
1958
  * - Hybrid rendering with both Canvas2D and WebGL support
@@ -1805,6 +1979,9 @@ declare module "littlejsengine" {
1805
1979
  * @memberof Draw */
1806
1980
  export let mainCanvas: HTMLCanvasElement;
1807
1981
  /** 2d context for mainCanvas
1982
+ * - Scaled by canvasPixelRatio, so drawing to it is in css pixels
1983
+ * - getImageData and putImageData ignore that scale and work in backing store
1984
+ * pixels, so use workReadCanvas to read pixels back instead of this
1808
1985
  * @type {CanvasRenderingContext2D}
1809
1986
  * @memberof Draw */
1810
1987
  export let mainContext: CanvasRenderingContext2D;
@@ -1833,7 +2010,9 @@ declare module "littlejsengine" {
1833
2010
  * @type {HTMLCanvasElement}
1834
2011
  * @memberof Draw */
1835
2012
  export let backgroundCanvas: HTMLCanvasElement;
1836
- /** The size of the main canvas (and other secondary canvases)
2013
+ /** The size of the main canvas (and other secondary canvases) in css pixels
2014
+ * - This is the screen space coordinate system, matching mousePos
2015
+ * - With canvasPixelRatio set the backing store is larger than this
1837
2016
  * @type {Vector2}
1838
2017
  * @memberof Draw */
1839
2018
  export let mainCanvasSize: Vector2;
@@ -2066,6 +2245,11 @@ declare module "littlejsengine" {
2066
2245
  * @param {boolean} [additive]
2067
2246
  * @memberof Draw */
2068
2247
  export function setAdditiveBlendMode(additive?: boolean): void;
2248
+ /** Set the Shader that 2D draws use from now on, none for the engine's own
2249
+ * - The object render loop sets each object's own shader, so this is for draws in gameRender and gameRenderPost
2250
+ * @param {Shader} [shader]
2251
+ * @memberof Draw */
2252
+ export function setShader(shader?: Shader): void;
2069
2253
  /** Set an extra canvas to composite behind the engine canvases when combining
2070
2254
  * Plugins that insert their own canvas below the LittleJS canvases should set
2071
2255
  * this so it appears in screenshots and video capture
@@ -2528,16 +2712,31 @@ declare module "littlejsengine" {
2528
2712
  * - Speech synthesis for text-to-speech
2529
2713
  * - Music playback with ZzFXM support
2530
2714
  * - Web Audio API integration with master gain control
2715
+ * - Sounds and the master bus can route through effects, see the audio effects plugin
2531
2716
  * @namespace Audio
2532
2717
  */
2533
2718
  /** Audio context used by the engine
2534
2719
  * @type {AudioContext}
2535
2720
  * @memberof Audio */
2536
2721
  export let audioContext: AudioContext;
2537
- /** Master gain node for all audio to pass through
2722
+ /** Master gain node for all audio to pass through, made at load so effects can connect to it any time
2538
2723
  * @type {GainNode}
2539
2724
  * @memberof Audio */
2540
2725
  export let audioMasterGain: GainNode;
2726
+ /** Anything with input and output audio nodes, like an effect from the audio effects plugin
2727
+ * @typedef {{input: AudioNode, output: AudioNode}} AudioEffectNodes
2728
+ * @memberof Audio */
2729
+ /** Route all sound through an effect between the master gain and the speakers
2730
+ * - Pass a node or an effect, or the first and last of a chain, each a node or an effect
2731
+ * - With one argument a node is both ends, and an effect uses its own input and output
2732
+ * - The output node is disconnected from everything else first, so it only feeds the speakers
2733
+ * - The two ends of a chain must already be connected to each other, like effectA.connect(effectB)
2734
+ * - Call with no arguments to remove the effect, an effect that was the master goes back to feeding the master gain
2735
+ * - Debug video capture records the end of the master chain, but loses its tap if the effect changes mid-capture
2736
+ * @param {AudioNode|AudioEffectNodes} [input] - Node or effect the master gain connects to
2737
+ * @param {AudioNode|AudioEffectNodes} [output] - Node or effect that connects to the audio destination, defaults to the input's output
2738
+ * @memberof Audio */
2739
+ export function setAudioMasterEffect(input?: AudioNode | AudioEffectNodes, output?: AudioNode | AudioEffectNodes): void;
2541
2740
  /** Default sample rate used for sounds
2542
2741
  * @default 44100
2543
2742
  * @memberof Audio */
@@ -2592,13 +2791,18 @@ declare module "littlejsengine" {
2592
2791
  /** @property {AudioBuffer} - Decoded audio shared by every play of this sound
2593
2792
  * @type {AudioBuffer} */
2594
2793
  sampleBuffer: AudioBuffer;
2595
- /** @private @type {Array<Array<number>|Float32Array>} */
2794
+ /** @private
2795
+ * @type {Array<Array<number>|Float32Array>} */
2596
2796
  private _sampleChannels;
2597
2797
  /** @property {number} - Percentage of this sound currently loaded, sounds
2598
2798
  * fetched from a url stay at 0 until decoding completes */
2599
2799
  loadedPercent: number;
2600
2800
  /** @property {SoundLoadCallback} - function to call when sound is loaded */
2601
2801
  onloadCallback: (sound: Sound) => Sound;
2802
+ /** @property {AudioNode|AudioEffectNodes} - Node or effect to route every play of this sound through instead of the master gain
2803
+ * - Where this sound's audio goes, unlike AudioEffect.output which is an effect's own node, effects chain with connect()
2804
+ * @type {AudioNode|AudioEffectNodes} */
2805
+ output: AudioNode | AudioEffectNodes;
2602
2806
  /** @param {Array<Array<number>|Float32Array>} sampleChannels */
2603
2807
  set sampleChannels(arg: (number[] | Float32Array)[]);
2604
2808
  /** Sample data for each channel
@@ -2621,6 +2825,14 @@ declare module "littlejsengine" {
2621
2825
  * @return {SoundInstance} - The sound instance, or undefined if sound is disabled, not loaded, or running in headless mode
2622
2826
  */
2623
2827
  play(pos?: Vector2, volume?: number, pitch?: number, randomnessScale?: number, loop?: boolean, paused?: boolean): SoundInstance;
2828
+ /** Play the sound on a loop, the same as play with loop on; stop or change it through the SoundInstance returned
2829
+ * @param {Vector2} [pos] - World space position to play the sound if any
2830
+ * @param {number} [volume] - How much to scale volume by
2831
+ * @param {number} [pitch] - How much to scale pitch by
2832
+ * @param {number} [randomnessScale] - How much to scale pitch randomness
2833
+ * @param {boolean} [paused] - Should the sound start paused
2834
+ * @return {SoundInstance} - The sound instance, or undefined if sound is disabled, not loaded, or running in headless mode */
2835
+ playLoop(pos?: Vector2, volume?: number, pitch?: number, randomnessScale?: number, paused?: boolean): SoundInstance;
2624
2836
  /** Play a music track that loops by default
2625
2837
  * @param {number} [volume] - Volume to play the music at
2626
2838
  * @param {boolean} [loop] - Should the music loop?
@@ -2630,7 +2842,7 @@ declare module "littlejsengine" {
2630
2842
  playMusic(volume?: number, loop?: boolean, paused?: boolean): SoundInstance;
2631
2843
  /** Play the sound as a musical note with a semitone offset
2632
2844
  * This can be used to play music with chromatic scales
2633
- * @param {number} [semitoneOffset=0] - How many semitones to offset pitch
2845
+ * @param {number} [semitoneOffset] - How many semitones to offset pitch
2634
2846
  * @param {Vector2} [pos] - World space position to play the sound if any
2635
2847
  * @param {number} [volume=1] - How much to scale volume by
2636
2848
  * @return {SoundInstance} - The sound instance
@@ -2691,15 +2903,26 @@ declare module "littlejsengine" {
2691
2903
  gainNode: GainNode;
2692
2904
  /** @property {AudioBufferSourceNode} - Source node of the audio */
2693
2905
  source: AudioBufferSourceNode;
2906
+ /** @property {AudioNode|AudioEffectNodes} - Node or effect to route this instance through, copied from the sound
2907
+ * @type {AudioNode|AudioEffectNodes} */
2908
+ output: AudioNode | AudioEffectNodes;
2694
2909
  onendedCallback: (source: any) => void;
2695
2910
  /** Start playing the sound instance from the offset time
2696
2911
  * @param {number} [offset] - Offset in seconds to start playback from
2697
2912
  */
2698
2913
  start(offset?: number): void;
2699
- /** Set the volume of this sound instance
2700
- * @param {number} volume */
2701
- setVolume(volume: number): void;
2702
- /** Stop this sound instance and reset position to the start */
2914
+ /** Set the volume of this sound instance, with an optional fade to it
2915
+ * - A fade ducks music under dialogue or cross fades two tracks without a click
2916
+ * @param {number} volume
2917
+ * @param {number} [fadeTime] - Seconds to fade to the new volume over */
2918
+ setVolume(volume: number, fadeTime?: number): void;
2919
+ /** Set the playback rate of this sound instance, its speed and pitch, while it plays
2920
+ * - A looping sound can follow something smoothly this way, like an engine with the speed
2921
+ * - A rate of 0 freezes the sound in place, its current time is not tracked until it moves again
2922
+ * @param {number} rate - 1 is normal, 2 is twice as fast and an octave up */
2923
+ setRate(rate: number): void;
2924
+ /** Stop this sound instance and reset position to the start
2925
+ * @param {number} [fadeTime] - Seconds to fade out over before stopping */
2703
2926
  stop(fadeTime?: number): void;
2704
2927
  /** Pause this sound instance */
2705
2928
  pause(): void;
@@ -2740,7 +2963,7 @@ declare module "littlejsengine" {
2740
2963
  export function speakStop(): void;
2741
2964
  /** Get frequency of a note on a musical scale
2742
2965
  * @param {number} semitoneOffset - How many semitones away from the root note
2743
- * @param {number} [rootFrequency=220] - Frequency at semitone offset 0
2966
+ * @param {number} [rootFrequency] - Frequency at semitone offset 0
2744
2967
  * @return {number} - The frequency of the note
2745
2968
  * @memberof Audio */
2746
2969
  export function getNoteFrequency(semitoneOffset: number, rootFrequency?: number): number;
@@ -2759,9 +2982,10 @@ declare module "littlejsengine" {
2759
2982
  * @param {GainNode} [gainNode] - Optional gain node for volume control while playing (disconnected when the sound ends)
2760
2983
  * @param {number} [offset] - Offset in seconds to start playback from
2761
2984
  * @param {AudioEndedCallback} [onended] - Callback for when the sound ends
2985
+ * @param {AudioNode|AudioEffectNodes} [output] - Node or effect to connect the gain to instead of the master gain
2762
2986
  * @return {AudioBufferSourceNode} - The source node of the sound played, may be undefined if play fails
2763
2987
  * @memberof Audio */
2764
- export function playSamples(sampleChannels: any[], volume?: number, rate?: number, pan?: number, loop?: boolean, sampleRate?: number, gainNode?: GainNode, offset?: number, onended?: AudioEndedCallback): AudioBufferSourceNode;
2988
+ export function playSamples(sampleChannels: any[], volume?: number, rate?: number, pan?: number, loop?: boolean, sampleRate?: number, gainNode?: GainNode, offset?: number, onended?: AudioEndedCallback, output?: AudioNode | AudioEffectNodes): AudioBufferSourceNode;
2765
2989
  /** Play an audio buffer with given settings
2766
2990
  * The buffer can be shared by any number of sounds playing at once
2767
2991
  * @param {AudioBuffer} buffer - The audio buffer to play
@@ -2772,9 +2996,10 @@ declare module "littlejsengine" {
2772
2996
  * @param {GainNode} [gainNode] - Optional gain node for volume control while playing (disconnected when the sound ends)
2773
2997
  * @param {number} [offset] - Offset in seconds to start playback from
2774
2998
  * @param {AudioEndedCallback} [onended] - Callback for when the sound ends
2999
+ * @param {AudioNode|AudioEffectNodes} [output] - Node or effect to connect the gain to instead of the master gain
2775
3000
  * @return {AudioBufferSourceNode} - The source node of the sound played, may be undefined if play fails
2776
3001
  * @memberof Audio */
2777
- export function playAudioBuffer(buffer: AudioBuffer, volume?: number, rate?: number, pan?: number, loop?: boolean, gainNode?: GainNode, offset?: number, onended?: AudioEndedCallback): AudioBufferSourceNode;
3002
+ export function playAudioBuffer(buffer: AudioBuffer, volume?: number, rate?: number, pan?: number, loop?: boolean, gainNode?: GainNode, offset?: number, onended?: AudioEndedCallback, output?: AudioNode | AudioEffectNodes): AudioBufferSourceNode;
2778
3003
  /** Copy arrays of samples into a new audio buffer
2779
3004
  * @param {Array} sampleChannels - Array of arrays of samples (for stereo playback)
2780
3005
  * @param {number} [sampleRate=44100] - Sample rate for the sound
@@ -2873,6 +3098,9 @@ declare module "littlejsengine" {
2873
3098
  color: Color;
2874
3099
  /** @property {Color} - Additive color to apply when rendered */
2875
3100
  additiveColor: any;
3101
+ /** @property {Shader|undefined} - Custom shader to render with, undefined for the engine's own
3102
+ * @type {Shader|undefined} */
3103
+ shader: Shader | undefined;
2876
3104
  /** @property {boolean} - Should the rendered tile flip along the y axis. Affects rendering and the local→world transform of attached children (a mirrored parent flips its children's localPos.x and localAngle). Does not affect this object's own physics, collision, or localToWorld/worldToLocal. */
2877
3105
  mirror: boolean;
2878
3106
  /** @property {boolean} - Has object been destroyed? */
@@ -2917,6 +3145,9 @@ declare module "littlejsengine" {
2917
3145
  isSolid: boolean;
2918
3146
  /** @property {boolean} - Object collides with raycasts */
2919
3147
  collideRaycast: boolean;
3148
+ /** @property {boolean} - Object is skipped by engineObjectsDestroy, for things that outlive a level like a camera
3149
+ * - Calling destroy on it still destroys it, and its children go with it either way */
3150
+ persistent: boolean;
2920
3151
  /** Update the object transform, called automatically by engine even when paused */
2921
3152
  updateTransforms(): void;
2922
3153
  /** Update the object physics, called automatically by engine once each frame. Can be overridden to stop or change how physics works for an object. */
@@ -2949,9 +3180,10 @@ declare module "littlejsengine" {
2949
3180
  collideWithTile(tileData: number, pos: Vector2): boolean;
2950
3181
  /** Called by the engine to check if an object collision should be resolved. Return true for physics to resolve the collision or false to ignore and resolve it manually.
2951
3182
  * @param {EngineObject} object - the object to test against
3183
+ * @param {Object} [push] - what it would take to move this object clear, a Vector3 from the 3D plugin, undefined in 2D
2952
3184
  * @return {boolean} - true if the collision should be resolved by modifying it's position and velocity
2953
3185
  */
2954
- collideWithObject(object: EngineObject): boolean;
3186
+ collideWithObject(object: EngineObject, push?: any): boolean;
2955
3187
  /** Get this object's up vector
2956
3188
  * @param {number} [scale] - length of the vector
2957
3189
  * @return {Vector2} */
@@ -3113,10 +3345,10 @@ declare module "littlejsengine" {
3113
3345
  * @param {boolean} [useWebGL] - Should this layer use WebGL for rendering
3114
3346
  */
3115
3347
  constructor(pos?: Vector2, size?: Vector2, angle?: number, renderOrder?: number, canvasSize?: Vector2, useWebGL?: boolean);
3116
- /** @property {HTMLCanvasElement} - The canvas used by this layer */
3117
- canvas: OffscreenCanvas;
3118
3348
  /** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this layer */
3119
3349
  context: OffscreenCanvasRenderingContext2D;
3350
+ /** @property {OffscreenCanvas} - The canvas used by this layer */
3351
+ canvas: OffscreenCanvas;
3120
3352
  /** @property {TextureInfo} - Texture info to use for this object rendering */
3121
3353
  textureInfo: TextureInfo;
3122
3354
  /** Destroy this canvas layer */
@@ -3656,6 +3888,10 @@ declare module "littlejsengine" {
3656
3888
  * - Supports shadertoy style post processing shaders
3657
3889
  * - call new PostProcessPlugin() to setup post processing
3658
3890
  * - can be enabled to pass other canvases through a final shader
3891
+ * - iResolution is the canvas backing store, so it grows with canvasPixelRatio
3892
+ * like shadertoy does. Effects that use it only for uv (p/iResolution.xy) are
3893
+ * unaffected, but ones that set a feature size from it, like scan lines, get
3894
+ * finer as the ratio rises. Divide by getCanvasPixelRatio() to pin them.
3659
3895
  * @namespace PostProcess
3660
3896
  */
3661
3897
  /** Global Post Process plugin object
@@ -3664,6 +3900,8 @@ declare module "littlejsengine" {
3664
3900
  export let postProcess: PostProcessPlugin;
3665
3901
  /**
3666
3902
  * Post Process Plugin - Applies a full screen shader to the rendered output
3903
+ * - Create it after any plugin that draws, since plugins render in the order they are made
3904
+ * and this one shades what is on the canvas when its turn comes
3667
3905
  * @memberof PostProcess
3668
3906
  */
3669
3907
  export class PostProcessPlugin {
@@ -3676,13 +3914,38 @@ declare module "littlejsengine" {
3676
3914
  * new PostProcessPlugin(shaderCode);
3677
3915
  */
3678
3916
  constructor(shaderCode: string, includeMainCanvas?: boolean, feedbackTexture?: boolean);
3679
- /** @property {WebGLProgram} - Shader for post processing */
3680
- shader: any;
3681
- /** @property {WebGLTexture} - Texture for post processing */
3682
- texture: any;
3683
- /** @property {WebGLVertexArrayObject} - Vertex array object */
3684
- vao: any;
3917
+ /** @property {WebGLProgram|undefined} - Shader for post processing
3918
+ * @type {WebGLProgram|undefined} */
3919
+ shader: WebGLProgram | undefined;
3920
+ /** @property {WebGLTexture|undefined} - Texture for post processing
3921
+ * @type {WebGLTexture|undefined} */
3922
+ texture: WebGLTexture | undefined;
3923
+ /** @property {WebGLVertexArrayObject|undefined} - Vertex array object
3924
+ * @type {WebGLVertexArrayObject|undefined} */
3925
+ vao: WebGLVertexArrayObject | undefined;
3685
3926
  }
3927
+ /**
3928
+ * Set up post processing with a bloom effect, so bright colors and lights glow
3929
+ * @param {number} [threshold] - Brightness where the glow starts, 0 is everything and 1 is only pure white
3930
+ * @param {number} [strength] - How much glow to add
3931
+ * @param {number} [size] - How far the glow spreads in pixels
3932
+ * @param {boolean} [includeMainCanvas] - Glow the 2D canvas too, off by default so HUD text stays crisp
3933
+ * @return {PostProcessPlugin}
3934
+ * @memberof PostProcess
3935
+ * @example
3936
+ * postProcessBloom(); // in gameInit, after any Render3DPlugin
3937
+ */
3938
+ export function postProcessBloom(threshold?: number, strength?: number, size?: number, includeMainCanvas?: boolean): PostProcessPlugin;
3939
+ /**
3940
+ * Shader code for a bloom effect, the bright parts of the image blurred back over it
3941
+ * - Pass it to PostProcessPlugin, or edit the string to build an effect on top of it
3942
+ * @param {number} [threshold] - Brightness where the glow starts, 0 is everything and 1 is only pure white
3943
+ * @param {number} [strength] - How much glow to add
3944
+ * @param {number} [size] - How far the glow spreads in pixels, which also sets how many samples it takes
3945
+ * @return {string}
3946
+ * @memberof PostProcess
3947
+ */
3948
+ export function postProcessBloomShader(threshold?: number, strength?: number, size?: number): string;
3686
3949
  /**
3687
3950
  * LittleJS Light System Plugin
3688
3951
  * - Adds 2D dynamic lighting to the scene
@@ -3713,7 +3976,7 @@ declare module "littlejsengine" {
3713
3976
  */
3714
3977
  export class LightSystemPlugin {
3715
3978
  /** Create the global light system plugin.
3716
- * @param {Vector2} [textureSize] - Size of the lightmap texture (defaults to mainCanvasSize)
3979
+ * @param {Vector2} [textureSize] - Size of the lightmap texture (defaults to mainCanvasSize, which is css pixels, so the lightmap is not scaled by canvasPixelRatio; pass mainCanvasSize.scale(getCanvasPixelRatio()) for a full resolution lightmap)
3717
3980
  * @param {Color} [ambientColor] - Color applied to unlit areas of the scene (defaults to BLACK = pitch dark). Set a small RGB like rgb(0.1,0.1,0.15) for a faint "moonlight" baseline so unlit areas aren't fully black.
3718
3981
  * @example
3719
3982
  * // simplest usage
@@ -3724,7 +3987,7 @@ declare module "littlejsengine" {
3724
3987
  enabled: boolean;
3725
3988
  /** @property {Color} - Baseline color applied to unlit areas of the scene. Defaults to BLACK (pitch dark). Set to a small RGB for a faint ambient. The lightmap is cleared to this color each frame, then lights add on top, then the result multiplies the scene. */
3726
3989
  ambientColor: Color;
3727
- /** @property {Vector2} - Size of the lightmap texture (set at construction; falls back to mainCanvasSize at init time) */
3990
+ /** @property {Vector2} - Size of the lightmap texture (set at construction; falls back to mainCanvasSize in css pixels at init time, so it is not scaled by canvasPixelRatio) */
3728
3991
  textureSize: Vector2;
3729
3992
  /** @property {WebGLTexture} - The lightmap texture */
3730
3993
  texture: any;
@@ -3774,7 +4037,7 @@ declare module "littlejsengine" {
3774
4037
  * @memberof ZzFXM
3775
4038
  * @example
3776
4039
  * // create some music
3777
- * const music_example = new Music(
4040
+ * const music_example = new ZzFXMusic(
3778
4041
  * [
3779
4042
  * [ // instruments
3780
4043
  * [,0,400] // simple note
@@ -3795,21 +4058,14 @@ declare module "littlejsengine" {
3795
4058
  * 90 // BPM
3796
4059
  * ]);
3797
4060
  *
3798
- * // play the music
3799
- * music_example.play();
4061
+ * // play the music on a loop
4062
+ * music_example.playMusic();
3800
4063
  */
3801
4064
  export class ZzFXMusic extends Sound {
3802
4065
  /** Create a music object and cache the zzfx music samples for later use
3803
4066
  * @param {[Array, Array, Array, number]} zzfxMusic - Array of zzfx music parameters
3804
4067
  */
3805
4068
  constructor(zzfxMusic: [any[], any[], any[], number]);
3806
- sampleChannels: any[];
3807
- /** Play the music that loops by default
3808
- * @param {number} [volume] - Volume to play the music at
3809
- * @param {boolean} [loop] - Should the music loop?
3810
- * @return {SoundInstance} - The sound instance
3811
- */
3812
- playMusic(volume?: number, loop?: boolean): SoundInstance;
3813
4069
  }
3814
4070
  /** Generate samples for a ZzFM song with given parameters
3815
4071
  * @param {Array} instruments - Array of ZzFX sound parameters
@@ -3819,6 +4075,183 @@ declare module "littlejsengine" {
3819
4075
  * @return {Array} - Left and right channel sample data
3820
4076
  * @memberof ZzFXM */
3821
4077
  export function zzfxM(instruments: any[], patterns: any[], sequence: any[], BPM?: number): any[];
4078
+ /**
4079
+ * Base class for audio effects, an input and output with a wet/dry mix between them
4080
+ * - Sounds connect to input, output goes to the master gain until connect() moves it
4081
+ * - Subclasses put their nodes between input and the wet gain with connectEffect
4082
+ * @memberof AudioEffects
4083
+ * @example
4084
+ * const cave = new AudioReverb(3, 2);
4085
+ * footstep.output = cave; // every play of this sound is in the cave
4086
+ */
4087
+ export class AudioEffect {
4088
+ /** Create an audio effect
4089
+ * @param {number} [mix] - Wet/dry balance, 0 is fully dry and 1 is fully wet */
4090
+ constructor(mix?: number);
4091
+ /** @property {GainNode} - Connect sounds to this node */
4092
+ input: GainNode;
4093
+ /** @property {GainNode} - This node carries the mixed result, send it somewhere with connect(), never by assigning here
4094
+ * - Unlike sound.output, which is where a sound's audio goes and can be set to an effect */
4095
+ output: GainNode;
4096
+ /** @property {GainNode} - Level of the unprocessed signal */
4097
+ dryGain: GainNode;
4098
+ /** @property {GainNode} - Level of the processed signal */
4099
+ wetGain: GainNode;
4100
+ /** @property {number} - Wet/dry balance, 0 is fully dry and 1 is fully wet */
4101
+ mix: number;
4102
+ /** Set the wet/dry balance
4103
+ * @param {number} mix - 0 is fully dry and 1 is fully wet
4104
+ * @param {number} [fadeTime] - Seconds to ramp over so the change doesn't click */
4105
+ setMix(mix: number, fadeTime?: number): void;
4106
+ /** Ramp one of this effect's params, keeping the effect running until the ramp is done
4107
+ * - The browser drops an effect from rendering while nothing plays through it, which
4108
+ * would freeze a ramp partway, so a silent source feeds the input for the ramp's length
4109
+ * @param {AudioParam} param - The param to ramp
4110
+ * @param {number} value - Where to ramp to
4111
+ * @param {number} [fadeTime] - Seconds to ramp over, 0 sets the value at once
4112
+ * @protected */
4113
+ protected rampParam(param: AudioParam, value: number, fadeTime?: number): void;
4114
+ /** Send this effect's output into another effect or audio node instead of the speakers
4115
+ * @param {AudioEffect|AudioNode} target - The next effect in the chain, or any audio node
4116
+ * @return {AudioEffect|AudioNode} - The target, so chains read left to right */
4117
+ connect(target: AudioEffect | AudioNode): AudioEffect | AudioNode;
4118
+ /** Stop sending this effect's output anywhere */
4119
+ disconnect(): void;
4120
+ /** Wire nodes between the input and the wet gain, for subclasses
4121
+ * @param {AudioNode} first - Node the input connects to
4122
+ * @param {AudioNode} [last=first] - Node that connects to the wet gain
4123
+ * @protected */
4124
+ protected connectEffect(first: AudioNode, last?: AudioNode): void;
4125
+ }
4126
+ /**
4127
+ * Filter effect, muffle sounds underwater or behind a wall
4128
+ * @extends AudioEffect
4129
+ * @memberof AudioEffects
4130
+ * @example
4131
+ * const muffle = new AudioFilter('lowpass', 400);
4132
+ * setAudioMasterEffect(muffle);
4133
+ * muffle.setFrequency(20000, .5); // sweep back to clear
4134
+ */
4135
+ export class AudioFilter extends AudioEffect {
4136
+ /** Create a filter effect
4137
+ * @param {BiquadFilterType} [type] - lowpass, highpass, bandpass, notch, etc.
4138
+ * @param {number} [frequency] - Cutoff or center frequency in Hz
4139
+ * @param {number} [q] - Resonance at the cutoff, higher is sharper
4140
+ * @param {number} [mix] - Wet/dry balance, 0 is fully dry and 1 is fully wet */
4141
+ constructor(type?: BiquadFilterType, frequency?: number, q?: number, mix?: number);
4142
+ /** @property {BiquadFilterNode} - The filter node */
4143
+ node: BiquadFilterNode;
4144
+ /** Set the cutoff or center frequency
4145
+ * @param {number} frequency - Frequency in Hz
4146
+ * @param {number} [fadeTime] - Seconds to sweep over */
4147
+ setFrequency(frequency: number, fadeTime?: number): void;
4148
+ /** Set the resonance at the cutoff
4149
+ * @param {number} q - Higher is sharper
4150
+ * @param {number} [fadeTime] - Seconds to ramp over */
4151
+ setQ(q: number, fadeTime?: number): void;
4152
+ }
4153
+ /**
4154
+ * Reverb effect, puts sounds in a room, cave, or hall
4155
+ * - The impulse response is generated, no audio file needed
4156
+ * @extends AudioEffect
4157
+ * @memberof AudioEffects
4158
+ * @example
4159
+ * const hall = new AudioReverb(4, 1.5, .4);
4160
+ * footstep.output = hall;
4161
+ */
4162
+ export class AudioReverb extends AudioEffect {
4163
+ /** Create a reverb effect
4164
+ * @param {number} [duration] - Seconds until the reverb tail is silent
4165
+ * @param {number} [decay] - How quickly the tail fades, higher is faster
4166
+ * @param {number} [mix] - Wet/dry balance, 0 is fully dry and 1 is fully wet */
4167
+ constructor(duration?: number, decay?: number, mix?: number);
4168
+ /** @property {ConvolverNode} - The convolver node */
4169
+ node: ConvolverNode;
4170
+ /** Change the room by rebuilding the impulse response
4171
+ * @param {number} duration - Seconds until the reverb tail is silent
4172
+ * @param {number} [decay] - How quickly the tail fades, higher is faster */
4173
+ setRoom(duration: number, decay?: number): void;
4174
+ /** Build a stereo impulse response of decaying noise
4175
+ * @param {number} duration - Seconds until silence
4176
+ * @param {number} decay - How quickly it fades, higher is faster
4177
+ * @return {AudioBuffer} */
4178
+ createImpulse(duration: number, decay: number): AudioBuffer;
4179
+ }
4180
+ /**
4181
+ * Delay effect, echoes that repeat and fade
4182
+ * @extends AudioEffect
4183
+ * @memberof AudioEffects
4184
+ * @example
4185
+ * const canyon = new AudioDelay(.4, .5);
4186
+ * shout.output = canyon;
4187
+ */
4188
+ export class AudioDelay extends AudioEffect {
4189
+ /** Create a delay effect
4190
+ * @param {number} [time] - Seconds between echoes, up to 5
4191
+ * @param {number} [feedback] - How much of each echo repeats, 0 to .95
4192
+ * @param {number} [mix] - Wet/dry balance, 0 is fully dry and 1 is fully wet */
4193
+ constructor(time?: number, feedback?: number, mix?: number);
4194
+ /** @property {DelayNode} - The delay node */
4195
+ node: DelayNode;
4196
+ /** @property {GainNode} - How much of the delayed signal feeds back in */
4197
+ feedbackGain: GainNode;
4198
+ /** Set the time between echoes
4199
+ * - Browsers hold a delay in a feedback loop to at least one render quantum, so 0 is not a bypass
4200
+ * @param {number} time - Seconds, up to 5
4201
+ * @param {number} [fadeTime] - Seconds to ramp over, pitch bends while it moves */
4202
+ setTime(time: number, fadeTime?: number): void;
4203
+ /** Set how much of each echo repeats, clamped below 1 so it always dies out
4204
+ * @param {number} feedback - 0 to .95
4205
+ * @param {number} [fadeTime] - Seconds to ramp over */
4206
+ setFeedback(feedback: number, fadeTime?: number): void;
4207
+ }
4208
+ /**
4209
+ * Distortion effect, overdrive for radios, damaged robots, and engines
4210
+ * @extends AudioEffect
4211
+ * @memberof AudioEffects
4212
+ * @example
4213
+ * const radio = new AudioDistortion(.8);
4214
+ * voice.output = radio;
4215
+ */
4216
+ export class AudioDistortion extends AudioEffect {
4217
+ /** Create a distortion effect
4218
+ * @param {number} [amount] - How hard to drive the signal, 0 is clean and 1 is crushed
4219
+ * @param {number} [mix] - Wet/dry balance, 0 is fully dry and 1 is fully wet */
4220
+ constructor(amount?: number, mix?: number);
4221
+ /** @property {WaveShaperNode} - The wave shaper node */
4222
+ node: WaveShaperNode;
4223
+ /** @property {number} - How hard the signal is driven, 0 is clean and 1 is crushed */
4224
+ amount: number;
4225
+ /** Set how hard to drive the signal, rebuilds the shaping curve
4226
+ * @param {number} amount - 0 is clean and 1 is crushed */
4227
+ setAmount(amount: number): void;
4228
+ }
4229
+ /**
4230
+ * Compressor effect, evens out loud and quiet so many sounds at once don't clip
4231
+ * - Meant for the master bus, it is not on by default
4232
+ * @extends AudioEffect
4233
+ * @memberof AudioEffects
4234
+ * @example
4235
+ * const compressor = new AudioCompressor;
4236
+ * setAudioMasterEffect(compressor);
4237
+ */
4238
+ export class AudioCompressor extends AudioEffect {
4239
+ /** Create a compressor effect
4240
+ * @param {number} [threshold] - Level in dB above which the signal is reduced
4241
+ * @param {number} [ratio] - How much to reduce it, 12 means 12 dB in becomes 1 dB out
4242
+ * @param {number} [mix] - Wet/dry balance, 0 is fully dry and 1 is fully wet */
4243
+ constructor(threshold?: number, ratio?: number, mix?: number);
4244
+ /** @property {DynamicsCompressorNode} - The compressor node */
4245
+ node: DynamicsCompressorNode;
4246
+ /** Set the level above which the signal is reduced
4247
+ * @param {number} threshold - Level in dB
4248
+ * @param {number} [fadeTime] - Seconds to ramp over */
4249
+ setThreshold(threshold: number, fadeTime?: number): void;
4250
+ /** Set how much the signal is reduced above the threshold
4251
+ * @param {number} ratio - 1 is no reduction, 20 is a hard limit
4252
+ * @param {number} [fadeTime] - Seconds to ramp over */
4253
+ setRatio(ratio: number, fadeTime?: number): void;
4254
+ }
3822
4255
  /**
3823
4256
  * LittleJS User Interface Plugin
3824
4257
  * - call new UISystemPlugin() to setup the UI system
@@ -5465,7 +5898,7 @@ declare module "littlejsengine" {
5465
5898
  * any object exposing a `lerp(other, percent) => sameType` method. The
5466
5899
  * callback receives the interpolated value (a number, or a fresh instance
5467
5900
  * for lerp-able types). Both endpoints must be the same type.
5468
- * @param {function(number|Vector2|Color):void} callback - Called with the interpolated value each frame
5901
+ * @param {function((number|Vector2|Color)):void} callback - Called with the interpolated value each frame
5469
5902
  * @param {number|Vector2|Color} [start=0] - Starting value
5470
5903
  * @param {number|Vector2|Color} [end=1] - Ending value
5471
5904
  * @param {number} [duration=1] - Duration in seconds
@@ -5473,13 +5906,13 @@ declare module "littlejsengine" {
5473
5906
  * @param {function(number):number} [options.ease] - Easing function (defaults to LINEAR)
5474
5907
  * @param {boolean} [options.useRealTime=false] - Advance even when the game is paused (matches Timer's useRealTime)
5475
5908
  * @param {boolean} [options.paused=false] - Start in paused state */
5476
- constructor(callback: (arg0: number | Vector2 | Color) => void, start?: number | Vector2 | Color, end?: number | Vector2 | Color, duration?: number, options?: {
5909
+ constructor(callback: (arg0: (number | Vector2 | Color)) => void, start?: number | Vector2 | Color, end?: number | Vector2 | Color, duration?: number, options?: {
5477
5910
  ease?: (arg0: number) => number;
5478
5911
  useRealTime?: boolean;
5479
5912
  paused?: boolean;
5480
5913
  });
5481
- /** @property {function(number|Vector2|Color):void} - Called with the interpolated value each frame */
5482
- callback: (arg0: number | Vector2 | Color) => void;
5914
+ /** @property {function((number|Vector2|Color)):void} - Called with the interpolated value each frame */
5915
+ callback: (arg0: (number | Vector2 | Color)) => void;
5483
5916
  /** @property {number|Vector2|Color} - Starting value */
5484
5917
  start: number | Vector2 | Color;
5485
5918
  /** @property {number|Vector2|Color} - Ending value */
@@ -5494,9 +5927,11 @@ declare module "littlejsengine" {
5494
5927
  useRealTime: boolean;
5495
5928
  /** @property {boolean} - If true, stop advancing until cleared */
5496
5929
  paused: boolean;
5497
- /** @private completion callback set by then(), loop(), pingPong(). */
5930
+ /** Completion callback set by then(), loop(), pingPong().
5931
+ * @private */
5498
5932
  private thenCallback;
5499
- /** @private remaining iterations including the current run (loop/pingPong only). */
5933
+ /** Remaining iterations including the current run (loop/pingPong only).
5934
+ * @private */
5500
5935
  private loopRemaining;
5501
5936
  /** Set the easing curve and return this for chaining.
5502
5937
  * @param {function(number):number} easeFn
@@ -5798,6 +6233,1622 @@ declare module "littlejsengine" {
5798
6233
  /** True if walkable and not blocked by cost. */
5799
6234
  isClear(): boolean;
5800
6235
  }
6236
+ /**
6237
+ * LittleJS 3D Math Plugin
6238
+ * - Vector3 and Matrix4 for 3D games and plugins
6239
+ * - Right handed, Y up, angles in radians
6240
+ * - Used by the Render3D plugin, but has no rendering dependencies
6241
+ * @namespace Math3D
6242
+ */
6243
+ /**
6244
+ * Create a 3D vector, can take 0, 1, 2 or 3 numbers
6245
+ * - vec3() is zero, vec3(s) fills all three, vec3(x, y) sets z to 0
6246
+ * @param {number} [x]
6247
+ * @param {number} [y]
6248
+ * @param {number} [z]
6249
+ * @return {Vector3}
6250
+ * @memberof Math3D
6251
+ */
6252
+ export function vec3(x?: number, y?: number, z?: number): Vector3;
6253
+ /**
6254
+ * Check if the object is a valid Vector3
6255
+ * @param {any} v
6256
+ * @return {boolean}
6257
+ * @memberof Math3D
6258
+ */
6259
+ export function isVector3(v: any): boolean;
6260
+ /**
6261
+ * Returns a random Vector3 of a given length, pointing any direction evenly, or within a cone around +Y
6262
+ * @param {number} [length]
6263
+ * @param {number} [coneAngle] - Half angle of the cone around +Y in radians, PI is every direction
6264
+ * @return {Vector3}
6265
+ * @memberof Math3D
6266
+ */
6267
+ export function randVector3(length?: number, coneAngle?: number): Vector3;
6268
+ /**
6269
+ * Returns a random Vector3 inside a sphere, spread evenly through its volume, the 3D twin of randInCircle
6270
+ * @param {number} [radius]
6271
+ * @param {number} [minRadius] - Leave a hollow middle this big
6272
+ * @return {Vector3}
6273
+ * @memberof Math3D
6274
+ */
6275
+ export function randInSphere(radius?: number, minRadius?: number): Vector3;
6276
+ /**
6277
+ * 3D Vector object, right handed with Y up
6278
+ * - Methods return new vectors except set and setFrom
6279
+ * @memberof Math3D
6280
+ * @example
6281
+ * const a = vec3(1, 2, 3);
6282
+ * const b = a.add(vec3(0, 1, 0)).normalize();
6283
+ */
6284
+ export class Vector3 {
6285
+ /** Create a 3D vector
6286
+ * @param {number} [x]
6287
+ * @param {number} [y]
6288
+ * @param {number} [z] */
6289
+ constructor(x?: number, y?: number, z?: number);
6290
+ /** @property {number} - X axis location */
6291
+ x: number;
6292
+ /** @property {number} - Y axis location */
6293
+ y: number;
6294
+ /** @property {number} - Z axis location */
6295
+ z: number;
6296
+ /** Sets values of this vector and returns self
6297
+ * @param {number} [x]
6298
+ * @param {number} [y]
6299
+ * @param {number} [z]
6300
+ * @return {Vector3} */
6301
+ set(x?: number, y?: number, z?: number): Vector3;
6302
+ /** Copies the values of another vector into this one and returns self
6303
+ * @param {Vector3} v
6304
+ * @return {Vector3} */
6305
+ setFrom(v: Vector3): Vector3;
6306
+ /** Returns a new vector that is a copy of this
6307
+ * @return {Vector3} */
6308
+ copy(): Vector3;
6309
+ /** Returns a copy of this vector plus the vector passed in
6310
+ * @param {Vector3} v
6311
+ * @return {Vector3} */
6312
+ add(v: Vector3): Vector3;
6313
+ /** Returns a copy of this vector minus the vector passed in
6314
+ * @param {Vector3} v
6315
+ * @return {Vector3} */
6316
+ subtract(v: Vector3): Vector3;
6317
+ /** Returns a copy of this vector times the vector passed in
6318
+ * @param {Vector3} v
6319
+ * @return {Vector3} */
6320
+ multiply(v: Vector3): Vector3;
6321
+ /** Returns a copy of this vector divided by the vector passed in
6322
+ * @param {Vector3} v
6323
+ * @return {Vector3} */
6324
+ divide(v: Vector3): Vector3;
6325
+ /** Returns a copy of this vector scaled by the number passed in
6326
+ * @param {number} s
6327
+ * @return {Vector3} */
6328
+ scale(s: number): Vector3;
6329
+ /** Returns the length of this vector
6330
+ * @return {number} */
6331
+ length(): number;
6332
+ /** Returns the length of this vector squared
6333
+ * @return {number} */
6334
+ lengthSquared(): number;
6335
+ /** Returns a copy of this vector reflected by a surface normal
6336
+ * @param {Vector3} normal - Surface normal, should be normalized
6337
+ * @param {number} [restitution] - How much to bounce, 1 is a perfect bounce, 0 slides along the surface
6338
+ * @return {Vector3} */
6339
+ reflect(normal: Vector3, restitution?: number): Vector3;
6340
+ /** Returns the distance from this vector to the vector passed in
6341
+ * @param {Vector3} v
6342
+ * @return {number} */
6343
+ distance(v: Vector3): number;
6344
+ /** Returns the distance squared from this vector to the vector passed in
6345
+ * @param {Vector3} v
6346
+ * @return {number} */
6347
+ distanceSquared(v: Vector3): number;
6348
+ /** Returns a new vector in the same direction with the length passed in, zero stays zero
6349
+ * @param {number} [length]
6350
+ * @return {Vector3} */
6351
+ normalize(length?: number): Vector3;
6352
+ /** Returns a new vector clamped to the length passed in
6353
+ * @param {number} [length]
6354
+ * @return {Vector3} */
6355
+ clampLength(length?: number): Vector3;
6356
+ /** Returns the dot product of this vector and the vector passed in
6357
+ * @param {Vector3} v
6358
+ * @return {number} */
6359
+ dot(v: Vector3): number;
6360
+ /** Returns a vector at right angles to both this and the one passed in
6361
+ * @param {Vector3} v
6362
+ * @return {Vector3} */
6363
+ cross(v: Vector3): Vector3;
6364
+ /** Returns a new vector interpolated between this and the vector passed in, percent is clamped to 0-1
6365
+ * @param {Vector3} v
6366
+ * @param {number} percent
6367
+ * @return {Vector3} */
6368
+ lerp(v: Vector3, percent: number): Vector3;
6369
+ /** Returns a new vector turned around an axis, counter clockwise when the axis points at you
6370
+ * @param {Vector3} axis - Unit length
6371
+ * @param {number} angle - Radians
6372
+ * @return {Vector3} */
6373
+ rotate(axis: Vector3, angle: number): Vector3;
6374
+ /** Returns a new vector turned around the X axis, the way a positive pitch in rotation3D turns things
6375
+ * @param {number} angle - Radians
6376
+ * @return {Vector3} */
6377
+ rotateX(angle: number): Vector3;
6378
+ /** Returns a new vector turned around the Y axis, the way a positive yaw in rotation3D turns things
6379
+ * @param {number} angle - Radians
6380
+ * @return {Vector3} */
6381
+ rotateY(angle: number): Vector3;
6382
+ /** Returns a new vector turned around the Z axis, the way a positive roll in rotation3D turns things
6383
+ * @param {number} angle - Radians
6384
+ * @return {Vector3} */
6385
+ rotateZ(angle: number): Vector3;
6386
+ /** Returns a new vector with the absolute value of each component
6387
+ * @return {Vector3} */
6388
+ abs(): Vector3;
6389
+ /** Returns a new vector with each component floored
6390
+ * @return {Vector3} */
6391
+ floor(): Vector3;
6392
+ /** Returns a new vector with each component rounded
6393
+ * @return {Vector3} */
6394
+ round(): Vector3;
6395
+ /** Returns a new vector snapped down to a grid, grid is the number of steps per unit like Vector2.snap
6396
+ * @param {number} grid - Snap steps per unit, 2 snaps to halves
6397
+ * @return {Vector3} */
6398
+ snap(grid: number): Vector3;
6399
+ /** Returns this point transformed by a matrix, translation included
6400
+ * @param {Matrix4} matrix
6401
+ * @return {Vector3} */
6402
+ transform(matrix: Matrix4): Vector3;
6403
+ /** Returns this direction transformed by a matrix, rotation and scale only
6404
+ * @param {Matrix4} matrix
6405
+ * @return {Vector3} */
6406
+ transformDirection(matrix: Matrix4): Vector3;
6407
+ /** Checks if this is a valid vector
6408
+ * @return {boolean} */
6409
+ isValid(): boolean;
6410
+ /** Returns a string representation of this vector for debugging
6411
+ * @param {number} [digits] - Number of digits to display
6412
+ * @return {string} */
6413
+ toString(digits?: number): string;
6414
+ }
6415
+ /**
6416
+ * 4x4 transform matrix for moving, rotating and scaling points in 3D
6417
+ * - Static builders like Matrix4.translation return a new matrix
6418
+ * - Methods on a matrix change it in place and return it, so calls can chain
6419
+ * - a.multiply(b) means b happens first, then a
6420
+ * - Stored the way WebGL wants it, so it can be sent to a shader as is
6421
+ * @memberof Math3D
6422
+ * @example
6423
+ * const m = buildMatrix(vec3(0, 1, 0), vec3(0, PI/2, 0)); // rotate then move up
6424
+ * const p = m.transformPoint(vec3(1, 0, 0));
6425
+ */
6426
+ export class Matrix4 {
6427
+ /** Returns a new identity matrix
6428
+ * @return {Matrix4} */
6429
+ static identity(): Matrix4;
6430
+ /** Returns a new translation matrix
6431
+ * @param {Vector3} v
6432
+ * @return {Matrix4} */
6433
+ static translation(v: Vector3): Matrix4;
6434
+ /** Returns a new rotation matrix, rolled first, then pitched, then yawed
6435
+ * @param {Vector3} euler - vec3(pitch, yaw, roll) in radians
6436
+ * @return {Matrix4} */
6437
+ static rotation(euler: Vector3): Matrix4;
6438
+ /** Returns a new scale matrix
6439
+ * @param {Vector3} v
6440
+ * @return {Matrix4} */
6441
+ static scaling(v: Vector3): Matrix4;
6442
+ /** Returns a new perspective projection, camera looks down -Z
6443
+ * @param {number} fov - Vertical field of view in radians
6444
+ * @param {number} aspect - Width divided by height
6445
+ * @param {number} near - Closest visible distance
6446
+ * @param {number} far - Furthest visible distance, Infinity is allowed
6447
+ * @return {Matrix4} */
6448
+ static perspective(fov: number, aspect: number, near: number, far: number): Matrix4;
6449
+ /** Returns a new orthographic projection, camera looks down -Z
6450
+ * @param {number} left - Edge of the visible box
6451
+ * @param {number} right - Edge of the visible box
6452
+ * @param {number} bottom - Edge of the visible box
6453
+ * @param {number} top - Edge of the visible box
6454
+ * @param {number} near - Closest visible distance
6455
+ * @param {number} far - Furthest visible distance, Infinity is not allowed here
6456
+ * @return {Matrix4} */
6457
+ static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): Matrix4;
6458
+ /** Returns the transform of something at eye turned to face target
6459
+ * - Invert it to get a view matrix for a camera there
6460
+ * @param {Vector3} eye
6461
+ * @param {Vector3} target
6462
+ * @param {Vector3} [up]
6463
+ * @return {Matrix4} */
6464
+ static lookAt(eye: Vector3, target: Vector3, up?: Vector3): Matrix4;
6465
+ /** Create a matrix, identity by default
6466
+ * @param {Float32Array|Array<number>} [m] - 16 column major values */
6467
+ constructor(m?: Float32Array | Array<number>);
6468
+ /** @property {Float32Array} - The 16 column major values */
6469
+ m: Float32Array;
6470
+ /** Returns a new matrix that is a copy of this
6471
+ * @return {Matrix4} */
6472
+ copy(): Matrix4;
6473
+ /** Multiply this matrix by another and return this, the other happens first
6474
+ * @param {Matrix4} matrix
6475
+ * @return {Matrix4} */
6476
+ multiply(matrix: Matrix4): Matrix4;
6477
+ /** Append a translation, returns self
6478
+ * @param {Vector3} v
6479
+ * @return {Matrix4} */
6480
+ translate(v: Vector3): Matrix4;
6481
+ /** Append a rotation, returns self
6482
+ * @param {Vector3} euler - vec3(pitch, yaw, roll) in radians
6483
+ * @return {Matrix4} */
6484
+ rotate(euler: Vector3): Matrix4;
6485
+ /** Append a scale, returns self
6486
+ * @param {Vector3} v
6487
+ * @return {Matrix4} */
6488
+ scale(v: Vector3): Matrix4;
6489
+ /** Transpose this matrix in place, returns self
6490
+ * @return {Matrix4} */
6491
+ transpose(): Matrix4;
6492
+ /** Flip this matrix so it undoes itself, returns this and does nothing if it cannot be inverted
6493
+ * @return {Matrix4} */
6494
+ invert(): Matrix4;
6495
+ /** Transform a point, translation included
6496
+ * @param {Vector3} v
6497
+ * @return {Vector3} */
6498
+ transformPoint(v: Vector3): Vector3;
6499
+ /** Transform a direction, rotation and scale only
6500
+ * @param {Vector3} v
6501
+ * @return {Vector3} */
6502
+ transformDirection(v: Vector3): Vector3;
6503
+ /** Returns the translation part of this matrix
6504
+ * @return {Vector3} */
6505
+ getTranslation(): Vector3;
6506
+ /** Returns a string representation of this matrix for debugging
6507
+ * @return {string} */
6508
+ toString(): string;
6509
+ }
6510
+ /**
6511
+ * Ray3D - A start point and a direction, what screenToRay returns and the raycast helpers take
6512
+ * - The direction need not be unit length, the distances that come back are in units of it
6513
+ * @memberof Math3D
6514
+ * @example
6515
+ * const ray = render3D.screenToRay(mousePosScreen);
6516
+ * const distance = raycastPlane(ray, vec3(), vec3(0, 1, 0));
6517
+ * if (distance !== undefined)
6518
+ * ball.pos3D = ray.getPosition(distance);
6519
+ */
6520
+ export class Ray3D {
6521
+ /** Create a ray
6522
+ * @param {Vector3} [origin]
6523
+ * @param {Vector3} [direction] - Defaults to -Z, forward */
6524
+ constructor(origin?: Vector3, direction?: Vector3);
6525
+ /** @property {Vector3} - Where the ray starts */
6526
+ origin: Vector3;
6527
+ /** @property {Vector3} - Which way it goes */
6528
+ direction: Vector3;
6529
+ /** Returns the point a distance along the ray
6530
+ * @param {number} distance - What the raycast helpers return
6531
+ * @return {Vector3} */
6532
+ getPosition(distance: number): Vector3;
6533
+ /** Returns a new ray that is a copy of this
6534
+ * @return {Ray3D} */
6535
+ copy(): Ray3D;
6536
+ }
6537
+ /**
6538
+ * Build a transform for an object from its position, rotation and scale
6539
+ * - A point is scaled first, then rotated, then moved, which is what you want for a game object
6540
+ * @param {Vector3} [pos]
6541
+ * @param {Vector3} [rotation] - vec3(pitch, yaw, roll) in radians
6542
+ * @param {Vector3} [scale]
6543
+ * @return {Matrix4}
6544
+ * @memberof Math3D
6545
+ */
6546
+ export function buildMatrix(pos?: Vector3, rotation?: Vector3, scale?: Vector3): Matrix4;
6547
+ /**
6548
+ * Check if a point is inside an axis aligned box, boundary is inclusive
6549
+ * @param {Vector3} point
6550
+ * @param {Vector3} pos - Center of the box
6551
+ * @param {Vector3} size - Full size of the box
6552
+ * @return {boolean}
6553
+ * @memberof Math3D
6554
+ */
6555
+ export function isPointInBox3D(point: Vector3, pos: Vector3, size: Vector3): boolean;
6556
+ /**
6557
+ * Check if two axis aligned boxes are overlapping, touching edges do not overlap
6558
+ * @param {Vector3} posA
6559
+ * @param {Vector3} sizeA - Full size of box A
6560
+ * @param {Vector3} posB
6561
+ * @param {Vector3} [sizeB] - Full size of box B, zero for a point
6562
+ * @return {boolean}
6563
+ * @memberof Math3D
6564
+ */
6565
+ export function isOverlapping3D(posA: Vector3, sizeA: Vector3, posB: Vector3, sizeB?: Vector3): boolean;
6566
+ /**
6567
+ * Returns the vector to move sphere A by so it no longer overlaps sphere B, or undefined
6568
+ * @param {Vector3} posA
6569
+ * @param {number} radiusA
6570
+ * @param {Vector3} posB
6571
+ * @param {number} radiusB
6572
+ * @return {Vector3|undefined}
6573
+ * @memberof Math3D
6574
+ */
6575
+ export function collideSphereSphere(posA: Vector3, radiusA: number, posB: Vector3, radiusB: number): Vector3 | undefined;
6576
+ /**
6577
+ * Returns the vector to move a sphere out of an axis aligned box, or undefined
6578
+ * @param {Vector3} pos - Sphere center
6579
+ * @param {number} radius
6580
+ * @param {Vector3} boxPos
6581
+ * @param {Vector3} boxSize - Full size of the box
6582
+ * @return {Vector3|undefined}
6583
+ * @memberof Math3D
6584
+ */
6585
+ export function collideSphereBox(pos: Vector3, radius: number, boxPos: Vector3, boxSize: Vector3): Vector3 | undefined;
6586
+ /**
6587
+ * Returns the vector to move a sphere back inside an axis aligned box, or undefined when it is all inside
6588
+ * - The inside out twin of collideSphereBox, for keeping things in a room or an arena
6589
+ * - A sphere too big for the box on some axis is held at the middle of it on that axis
6590
+ * @param {Vector3} pos - Sphere center
6591
+ * @param {number} radius
6592
+ * @param {Vector3} boxPos
6593
+ * @param {Vector3} boxSize - Full size of the box
6594
+ * @return {Vector3|undefined}
6595
+ * @memberof Math3D
6596
+ */
6597
+ export function collideSphereInBox(pos: Vector3, radius: number, boxPos: Vector3, boxSize: Vector3): Vector3 | undefined;
6598
+ /**
6599
+ * Returns the vector to move a sphere out of a vertical cylinder, or undefined
6600
+ * @param {Vector3} pos - Sphere center
6601
+ * @param {number} radius
6602
+ * @param {Vector3} cylinderPos
6603
+ * @param {number} cylinderRadius
6604
+ * @param {number} cylinderHeight - Full height along Y
6605
+ * @return {Vector3|undefined}
6606
+ * @memberof Math3D
6607
+ */
6608
+ export function collideSphereCylinder(pos: Vector3, radius: number, cylinderPos: Vector3, cylinderRadius: number, cylinderHeight: number): Vector3 | undefined;
6609
+ /**
6610
+ * Returns the vector to move box A by so it no longer overlaps box B, the shortest way out, or undefined
6611
+ * - The 3D twin of collideBoxBox
6612
+ * @param {Vector3} posA
6613
+ * @param {Vector3} sizeA - Full size of box A
6614
+ * @param {Vector3} posB
6615
+ * @param {Vector3} sizeB - Full size of box B
6616
+ * @return {Vector3|undefined}
6617
+ * @memberof Math3D
6618
+ */
6619
+ export function collideBoxBox3D(posA: Vector3, sizeA: Vector3, posB: Vector3, sizeB: Vector3): Vector3 | undefined;
6620
+ /**
6621
+ * Returns the distance along the ray to the first intersection with a sphere, or undefined
6622
+ * - The hit is ray.getPosition(distance), a direction that is not unit length scales the distance
6623
+ * - A ray starting inside the sphere is already there, so it gets back 0
6624
+ * @param {Ray3D} ray
6625
+ * @param {Vector3} pos - Sphere center
6626
+ * @param {number} radius
6627
+ * @return {number|undefined}
6628
+ * @memberof Math3D
6629
+ */
6630
+ export function raycastSphere(ray: Ray3D, pos: Vector3, radius: number): number | undefined;
6631
+ /**
6632
+ * Returns the distance along the ray to a plane, or undefined if parallel or behind
6633
+ * - The hit is ray.getPosition(distance), a direction that is not unit length scales the distance
6634
+ * @param {Ray3D} ray
6635
+ * @param {Vector3} planePos
6636
+ * @param {Vector3} planeNormal
6637
+ * @return {number|undefined}
6638
+ * @memberof Math3D
6639
+ */
6640
+ export function raycastPlane(ray: Ray3D, planePos: Vector3, planeNormal: Vector3): number | undefined;
6641
+ /**
6642
+ * Returns the distance along the ray to the first intersection with an axis aligned box, or undefined
6643
+ * - The hit is ray.getPosition(distance), a direction that is not unit length scales the distance
6644
+ * - A ray starting inside the box is already there, so it gets back 0
6645
+ * @param {Ray3D} ray
6646
+ * @param {Vector3} pos - Center of the box
6647
+ * @param {Vector3} size - Full size of the box
6648
+ * @return {number|undefined}
6649
+ * @memberof Math3D
6650
+ */
6651
+ export function raycastBox(ray: Ray3D, pos: Vector3, size: Vector3): number | undefined;
6652
+ /**
6653
+ * LittleJS 3D Rendering Plugin
6654
+ * - Adds a 3D scene that draws into the same WebGL canvas as the 2D game
6655
+ * - Call new Render3DPlugin() in gameInit, then move render3D.camera and make EngineObject3D objects
6656
+ * - EngineObject3D is an EngineObject with a 3D position, rotation and mesh
6657
+ * - The 3D scene draws under the 2D sprites, so HUD and text land on top
6658
+ * - Lighting is the sun plus ambient, with optional extra lights, fog and shadows
6659
+ * - Any object or draw can bring its own Shader, a mainImage snippet the lighting then applies to
6660
+ * - Build shapes with buildBox, buildSphere and friends, or load a model with loadOBJ
6661
+ * - Requires the Math3D plugin
6662
+ * @namespace Render3D
6663
+ */
6664
+ /** Global Render3D plugin object
6665
+ * @type {Render3DPlugin}
6666
+ * @memberof Render3D */
6667
+ export let render3D: Render3DPlugin;
6668
+ /**
6669
+ * Render3D Plugin - The 3D renderer, camera, lights, shadows and fog
6670
+ * - There is one of these, in the global render3D
6671
+ * - It draws the 3D scene before gameRender, so 2D drawing lands on top
6672
+ * - Set renderAfter2D to draw the 3D scene over the 2D scene instead
6673
+ * - Settings like lighting and specular are read as each thing draws
6674
+ * - Every object sets them from its own flags, so you rarely touch them
6675
+ * @memberof Render3D
6676
+ * @example
6677
+ * new Render3DPlugin;
6678
+ * render3D.camera.pos = vec3(0, 5, 10);
6679
+ * render3D.camera.lookAt(vec3());
6680
+ * new EngineObject3D(vec3(), buildBox());
6681
+ */
6682
+ export class Render3DPlugin {
6683
+ /** @property {Camera3D} - The camera */
6684
+ camera: Camera3D;
6685
+ /** @property {Vector3} - Direction toward the sun, where its light comes from, like a directional Light3D;
6686
+ * read at each draw, and any length will do, the shading and the shadows normalize it themselves;
6687
+ * the sun is the one light that casts shadows and makes specular highlights */
6688
+ sunDirection: Vector3;
6689
+ /** @property {Color} - Sunlight color */
6690
+ sunColor: Color;
6691
+ /** @property {Color} - Ambient light color */
6692
+ ambientColor: Color;
6693
+ /** @property {Color|undefined} - Fog color, uses canvasClearColor when undefined
6694
+ * @type {Color|undefined} */
6695
+ fogColor: Color | undefined;
6696
+ /** @property {number} - Distance from the camera where fog starts */
6697
+ fogStart: number;
6698
+ /** @property {number} - Distance from the camera where fog is total, 0 disables fog */
6699
+ fogEnd: number;
6700
+ /** @property {Vector3} - Added to the velocity3D of every object with a mass each frame, scaled by its gravityScale; sync2D objects use the 2D gravity */
6701
+ gravity: Vector3;
6702
+ /** @property {number|HeightMap|Function} - Floor for objects with a softShadow: a height, a HeightMap, or (x, z) => y
6703
+ * @type {number|HeightMap|Function} */
6704
+ softShadowHeight: number | HeightMap | Function;
6705
+ /** @property {boolean} - Default for every builder's smooth argument: true for smooth vertex normals, false for flat faces */
6706
+ smoothShading: boolean;
6707
+ /** @property {boolean} - Cast real shadows from the sun, off by default and free when off */
6708
+ shadows: boolean;
6709
+ /** @property {number} - Size of the shadow map in pixels, bigger is sharper and slower */
6710
+ shadowMapSize: number;
6711
+ /** @property {number} - World size the shadow map covers around shadowCenter, smaller is sharper; it is a square
6712
+ * facing the light, so it turns as the light does, and about 1.5 times an area's width covers it from any angle */
6713
+ shadowRange: number;
6714
+ /** @property {Vector3|undefined} - Center of the shadowed area, read each frame, undefined follows the camera
6715
+ * @type {Vector3|undefined} */
6716
+ shadowCenter: Vector3 | undefined;
6717
+ /** @property {number} - Stops surfaces shadowing themselves, raise for speckles, lower if shadows drift off */
6718
+ shadowBias: number;
6719
+ /** @property {number} - How much to blur the shadow edges */
6720
+ shadowSoftness: number;
6721
+ /** @property {boolean} - Apply lighting, when false draws plain vertex color times texture and casts no shadow;
6722
+ * off for billboards, lines, ribbons and soft discs, an object sets emissive instead */
6723
+ lighting: boolean;
6724
+ /** @property {number} - How much a surface lights itself, set per object by its emissive */
6725
+ emissive: number;
6726
+ /** @property {boolean} - Additive blending instead of alpha, in the transparent stage */
6727
+ additive: boolean;
6728
+ /** @property {boolean} - Test against the depth buffer, reset to true before each object and callback */
6729
+ depthTest: boolean;
6730
+ /** @property {boolean} - Write to the depth buffer, owned by the stages: on for opaque, off for transparent */
6731
+ depthWrite: boolean;
6732
+ cullBackFaces: boolean;
6733
+ mirrored: boolean;
6734
+ /** @property {number} - Strength of the highlight where the sunlight reflects, 0 is none and 1 adds the sun's full color at its brightest; its size is fixed */
6735
+ specular: number;
6736
+ /** @property {Shader|undefined} - Custom Shader for the next draws, set from each object's shader; undefined draws with the plugin's own
6737
+ * @type {Shader|undefined} */
6738
+ shader: Shader | undefined;
6739
+ /** @property {boolean} - Darken by the shadow map when shadows are on, turn it off for things that should stay lit inside a shadow */
6740
+ receiveShadow: boolean;
6741
+ /** @property {Function|undefined} - Draw solid world here, it runs again for shadows so only draw in it
6742
+ * @type {Function|undefined} */
6743
+ onRenderOpaque: Function | undefined;
6744
+ /** @property {Function|undefined} - Draw see through things here, like glows, billboards and soft shadows
6745
+ * @type {Function|undefined} */
6746
+ onRenderTransparent: Function | undefined;
6747
+ /** @property {Mesh|undefined} - Sky dome from buildSky or setSky, drawn around the camera behind everything
6748
+ * @type {Mesh|undefined} */
6749
+ sky: Mesh | undefined;
6750
+ /** @property {boolean} - Draw the 3D scene on top of the 2D scene instead of under it */
6751
+ renderAfter2D: boolean;
6752
+ /** @property {boolean} - Draw see through things far to near so they blend correctly */
6753
+ sortTransparent: boolean;
6754
+ /** @property {boolean} - Skip meshes whose bounding sphere is outside the view */
6755
+ frustumCulling: boolean;
6756
+ /** @property {boolean} - Draw every use of a mesh in the opaque stage as one instanced call, mesh.instanced overrides it per mesh */
6757
+ instancing: boolean;
6758
+ /** @property {boolean} - Sample textures through mipmaps so they do not shimmer in the distance, false uses each texture's own filtering like 2D */
6759
+ mipmaps: boolean;
6760
+ /** @property {boolean} - Draw state: keep texture pixels hard edged, no mipmaps and no blending between them, set per object by pixelated */
6761
+ pixelated: boolean;
6762
+ /** @property {number} - Anisotropic filtering for textures seen at an angle, 1 to 16, 1 is off; needs mipmaps */
6763
+ anisotropy: number;
6764
+ /** @property {Mesh} - A box of size 1 that drawBox uses, for any object that is a box; set the object's scale3D
6765
+ * and color instead of editing the mesh, which would change every box that uses it */
6766
+ boxMesh: Mesh;
6767
+ /** @property {Mesh} - A smooth sphere of diameter 1 that drawSphere uses, shared the same way as boxMesh */
6768
+ sphereMesh: Mesh;
6769
+ /** @property {Mesh} - A flat square of size 1 facing +Y, seen from above only, for floors, water and decals;
6770
+ * stand it up with the object's rotation3D, and size it with scale3D */
6771
+ planeMesh: Mesh;
6772
+ /** @property {Mesh} - The same square seen and lit from both sides, for signs, cards and leaves */
6773
+ planeMeshDoubleSided: Mesh;
6774
+ /** @property {boolean} - True while the 3D pass is running, 3D draws are only valid then */
6775
+ isRendering: boolean;
6776
+ /** @property {boolean} - True while the shadow map is being drawn, draws go to the depth only shader */
6777
+ shadowPass: boolean;
6778
+ /** @property {Matrix4} - This frame's view matrix */
6779
+ viewMatrix: Matrix4;
6780
+ /** @property {Matrix4} - This frame's projection matrix */
6781
+ projectionMatrix: Matrix4;
6782
+ /** @property {Matrix4} - This frame's combined view projection */
6783
+ viewProjection: Matrix4;
6784
+ /** @property {Matrix4} - This frame's light view projection for the shadow map */
6785
+ shadowMatrix: Matrix4;
6786
+ /** @property {Vector3} - Camera right axis this frame */
6787
+ cameraRight: Vector3;
6788
+ /** @property {Vector3} - Camera up axis this frame */
6789
+ cameraUp: Vector3;
6790
+ /** @property {Vector3} - Camera forward axis this frame */
6791
+ cameraForward: Vector3;
6792
+ cameraBack: Vector3;
6793
+ blend: boolean;
6794
+ frustumPlanes: any[];
6795
+ shadowPlanes: any[];
6796
+ program: any;
6797
+ currentProgram: any;
6798
+ lightCount: number;
6799
+ shadowShader: any;
6800
+ vao: any;
6801
+ whiteTexture: any;
6802
+ samplers: any[];
6803
+ samplerKey: any;
6804
+ mipmapped: WeakSet<object>;
6805
+ shadowTexture: any;
6806
+ shadowFramebuffer: any;
6807
+ shadowTextureSize: number;
6808
+ contextGeneration: number;
6809
+ uniforms: Map<any, any>;
6810
+ uniformValues: {};
6811
+ shadowMapDrawn: boolean;
6812
+ passIsDefault: boolean;
6813
+ lightPositions: Float32Array;
6814
+ lightColors: Float32Array;
6815
+ streamBuffer: any;
6816
+ instanceBuffers: any[];
6817
+ instanceBufferIndex: number;
6818
+ instanceMeshes: any[];
6819
+ attribValues: any[];
6820
+ streamData: ArrayBuffer;
6821
+ streamFloats: Float32Array;
6822
+ streamInts: Uint32Array;
6823
+ streamCount: number;
6824
+ streamTileInfo: any;
6825
+ streamState: any;
6826
+ capture: Mesh;
6827
+ transparentQueue: any[];
6828
+ /** Rebuild the view and projection matrices from the camera, called automatically each frame
6829
+ * @param {number} [aspect] - Width over height, defaults to the main canvas */
6830
+ updateMatrices(aspect?: number): void;
6831
+ /** Where a world point lands on screen as -1 to 1 across and up, with z as depth
6832
+ * - Uses this frame's camera, call updateMatrices first if the camera just moved
6833
+ * @param {Vector3} pos
6834
+ * @return {Vector3|undefined} - undefined when behind the camera or closer than the near plane */
6835
+ worldToClip(pos: Vector3): Vector3 | undefined;
6836
+ /** Project a world point to screen space pixels, same space as mousePosScreen
6837
+ * - The opposite of screenToRay, and it takes the same canvas so the pair agree
6838
+ * @param {Vector3} pos
6839
+ * @param {Vector2} [canvasSize] - Defaults to the main canvas size, as in screenToRay;
6840
+ * the projection is whatever updateMatrices last built, which screenToRay does for its canvas
6841
+ * @return {Vector2|undefined} - undefined when behind the camera or closer than the near plane */
6842
+ worldToScreen(pos: Vector3, canvasSize?: Vector2): Vector2 | undefined;
6843
+ /** Get the world ray under a screen position, for clicking on things in 3D
6844
+ * - Uses the camera where it is right now, so it is fine to call from gameUpdate
6845
+ * - It brings the view matrices up to date for that canvas, so worldToScreen stays its exact opposite
6846
+ * @param {Vector2} screenPos - Same space as mousePosScreen
6847
+ * @param {Vector2} [canvasSize] - Defaults to the main canvas size
6848
+ * @return {Ray3D} - Starts at the camera with a unit direction, or on the camera plane when orthographic */
6849
+ screenToRay(screenPos: Vector2, canvasSize?: Vector2): Ray3D;
6850
+ /** Where a screen position lands on a flat ground plane, for top down games; use HeightMap.raycast for terrain
6851
+ * @param {Vector2} screenPos - Same space as mousePosScreen
6852
+ * @param {number} [groundHeight] - World height of the ground plane
6853
+ * @param {Vector2} [canvasSize] - Defaults to the main canvas size, as in screenToRay
6854
+ * @return {Vector3|undefined} - undefined when the ray misses the plane */
6855
+ screenToGround(screenPos: Vector2, groundHeight?: number, canvasSize?: Vector2): Vector3 | undefined;
6856
+ /** Find the nearest object under a screen position or along a ray, for clicking on things
6857
+ * - Each object is tested as a sphere around its mesh, or around a sprite's size3D, not triangle by triangle
6858
+ * - engineObjectsRaycast3D is the other half of this, every object along a ray instead of the nearest
6859
+ * @param {Vector2|Ray3D} from - A screen position like mousePosScreen, or a ray to look along
6860
+ * @param {Array<EngineObject>} [objects] - Defaults to every object; only those with a mesh or a sprite count
6861
+ * @return {{object: EngineObject3D, distance: number}|undefined} */
6862
+ pick(from: Vector2 | Ray3D, objects?: Array<EngineObject>): {
6863
+ object: EngineObject3D;
6864
+ distance: number;
6865
+ } | undefined;
6866
+ /** Play a sound at a 3D position, quieter with distance from the camera and panned by its side, like Sound.play with a 2D position
6867
+ * @param {Sound} sound
6868
+ * @param {Vector3} pos3D
6869
+ * @param {number} [volume]
6870
+ * @param {number} [pitch]
6871
+ * @param {number} [randomnessScale] - How much to scale pitch randomness
6872
+ * @param {boolean} [loop]
6873
+ * @return {SoundInstance|undefined} - undefined when out of range or sound is off */
6874
+ playSound(sound: Sound, pos3D: Vector3, volume?: number, pitch?: number, randomnessScale?: number, loop?: boolean): SoundInstance | undefined;
6875
+ /** Play a sound on a loop at a 3D position, the same as playSound with loop on
6876
+ * - Its volume and pan are set when it starts, change or stop it through the SoundInstance returned
6877
+ * @param {Sound} sound
6878
+ * @param {Vector3} pos3D
6879
+ * @param {number} [volume]
6880
+ * @param {number} [pitch]
6881
+ * @param {number} [randomnessScale] - How much to scale pitch randomness
6882
+ * @return {SoundInstance|undefined} - undefined when out of range or sound is off */
6883
+ playSoundLoop(sound: Sound, pos3D: Vector3, volume?: number, pitch?: number, randomnessScale?: number): SoundInstance | undefined;
6884
+ /** Is any part of a sphere on screen this frame, the test that skips meshes the camera cannot see
6885
+ * - While the shadow map is drawing it tests the shadow area instead
6886
+ * @param {Vector3} center
6887
+ * @param {number} radius
6888
+ * @return {boolean} */
6889
+ isSphereVisible(center: Vector3, radius: number): boolean;
6890
+ /** Draw a mesh with the current draw state, batched with its other uses in the opaque stage when instancing is on
6891
+ * @param {Mesh} mesh
6892
+ * @param {Matrix4|Vector3} [matrix] - Object transform, or just a position to draw it at
6893
+ * @param {TileInfo|TextureInfo} [tileInfo] - Texture, mesh uvs map across the tile or the whole texture
6894
+ * @param {Color} [color] - Tint */
6895
+ drawMesh(mesh: Mesh, matrix?: Matrix4 | Vector3, tileInfo?: TileInfo | TextureInfo, color?: Color): any;
6896
+ /** Draw a triangle strip, batched into the stream with the current draw state
6897
+ * - Strip order: the first three points make a triangle, then each point makes another with the two before it
6898
+ * - List the first three points counter clockwise as seen from the front, or the face points away
6899
+ * and may vanish when back faces are culled
6900
+ * - inside a bake the strip goes into the mesh instead, in the transparent stage it is queued for sorting
6901
+ * @param {Array<Vector3>} points - In strip order
6902
+ * @param {Vector3|Array<Vector3>} [normals] - One for all or one per point, default up
6903
+ * @param {Vector2|Array<Vector2>} [uvs] - One for all or one per point, 0-1 across the tile
6904
+ * @param {Color|Array<Color>} [colors] - One for all or one per point, vertex colors come before the texture
6905
+ * @param {TileInfo|TextureInfo} [tileInfo] - Texture for this strip */
6906
+ drawStrip(points: Array<Vector3>, normals?: Vector3 | Array<Vector3>, uvs?: Vector2 | Array<Vector2>, colors?: Color | Array<Color>, tileInfo?: TileInfo | TextureInfo): any;
6907
+ /** Draw a strip with lighting off, for camera facing shapes where the light direction means nothing
6908
+ * @param {Array<Vector3>} points - Strip order
6909
+ * @param {Vector3|Array<Vector3>} [normals]
6910
+ * @param {Vector2|Array<Vector2>} [uvs]
6911
+ * @param {Color|Array<Color>} [colors]
6912
+ * @param {TileInfo|TextureInfo} [tileInfo] */
6913
+ drawStripUnlit(points: Array<Vector3>, normals?: Vector3 | Array<Vector3>, uvs?: Vector2 | Array<Vector2>, colors?: Color | Array<Color>, tileInfo?: TileInfo | TextureInfo): void;
6914
+ /** Draw the pending stream vertices as one strip with the state they were drawn under, called automatically when needed */
6915
+ flush(): void;
6916
+ /** Build a mesh once out of draw calls, instead of redrawing the shapes every frame
6917
+ * - Call the same drawStrip, drawQuad and drawBox calls inside, and get a mesh back
6918
+ * - Strips inside a bake ignore their tileInfo, the finished mesh picks the texture when it draws
6919
+ * - drawMesh, drawBox and drawSphere copy their mesh in, moved and tinted, their tileInfo dropped too
6920
+ * - The mesh skips its back faces like any, set doubleSided when what was drawn is open
6921
+ * @param {Function} drawFunction
6922
+ * @return {Mesh} */
6923
+ bake(drawFunction: Function): Mesh;
6924
+ /** Draw a layer's objects, solid ones first and see through ones after, called automatically
6925
+ * - The main layer also draws the sky, the render callbacks and the debug shapes
6926
+ * @param {Array<EngineObject3D>} objects
6927
+ * @param {boolean} [isDefault] */
6928
+ renderStages(objects: Array<EngineObject3D>, isDefault?: boolean): void;
6929
+ /** Queue a draw for the transparent stage, replayed far to near with the current draw state, or draw it now when sorting is off
6930
+ * @param {Vector3} pos - Where the draw is, for sorting
6931
+ * @param {Function} draw */
6932
+ queueTransparent(pos: Vector3, draw: Function): any;
6933
+ /** Draw the queued transparent draws far to near with the state each was drawn under, called automatically at the end of the transparent stage */
6934
+ flushTransparentQueue(): void;
6935
+ /** Draw render3D.sky around the camera, unlit, unfogged and behind everything, called automatically by the pass */
6936
+ drawSky(): void;
6937
+ /** Rebuild the light's view projection around the shadow center, called automatically each frame shadows are on */
6938
+ updateShadowMatrix(): void;
6939
+ /** Build a sky dome, set it as the sky and set the fog color to the horizon color
6940
+ * @param {Color} [topColor] - Straight up
6941
+ * @param {Color} [horizonColor] - Level with the camera
6942
+ * @param {Color} [bottomColor] - Straight down, defaults to the horizon color
6943
+ * @return {Mesh} - The dome, also in render3D.sky */
6944
+ setSky(topColor?: Color, horizonColor?: Color, bottomColor?: Color): Mesh;
6945
+ /** Set where fog starts and ends, and its color
6946
+ * @param {number} fogStart - Distance from the camera where fog starts
6947
+ * @param {number} fogEnd - Distance where fog is total, 0 disables fog
6948
+ * @param {Color} [fogColor] - Leaves the color alone when not passed, setSky sets it to the horizon */
6949
+ setFog(fogStart: number, fogEnd: number, fogColor?: Color): void;
6950
+ /** Draw a box, untextured, for blocking out a scene without meshes or objects
6951
+ * @param {Vector3} pos - Center
6952
+ * @param {Vector3|number} [size] - Full size, a number for a cube
6953
+ * @param {Color} [color]
6954
+ * @param {Vector3} [rotation] - vec3(pitch, yaw, roll) */
6955
+ drawBox(pos: Vector3, size?: Vector3 | number, color?: Color, rotation?: Vector3): void;
6956
+ /** Draw a sphere, untextured and smooth shaded
6957
+ * @param {Vector3} pos - Center
6958
+ * @param {number} [size] - Diameter
6959
+ * @param {Color} [color] */
6960
+ drawSphere(pos: Vector3, size?: number, color?: Color): void;
6961
+ /** Draw a flat square that always faces the camera, unlit so it keeps its own colors
6962
+ * - Draw it from onRenderTransparent or a transparent object so it can fade
6963
+ * @param {Vector3} pos - Center
6964
+ * @param {Vector2} [size] - World units
6965
+ * @param {TileInfo|TextureInfo} [tileInfo]
6966
+ * @param {Color} [color]
6967
+ * @param {number} [angle] - Rotation in the camera plane, counter clockwise
6968
+ * @param {boolean} [upright] - Stand on world up and only turn to face the camera, for sprites on the ground */
6969
+ drawBillboard(pos: Vector3, size?: Vector2, tileInfo?: TileInfo | TextureInfo, color?: Color, angle?: number, upright?: boolean): any;
6970
+ /** Draw a quad from four corners in loop order, counter clockwise seen from the front, a is the top left of the texture
6971
+ * @param {Vector3} a
6972
+ * @param {Vector3} b
6973
+ * @param {Vector3} c
6974
+ * @param {Vector3} d
6975
+ * @param {TileInfo|TextureInfo} [tileInfo]
6976
+ * @param {Color|Array<Color>} [color] - One for all or one per corner */
6977
+ drawQuad(a: Vector3, b: Vector3, c: Vector3, d: Vector3, tileInfo?: TileInfo | TextureInfo, color?: Color | Array<Color>): void;
6978
+ /** Draw a triangle, counter clockwise from outside is the front
6979
+ * @param {Vector3} a
6980
+ * @param {Vector3} b
6981
+ * @param {Vector3} c
6982
+ * @param {Color} [color] */
6983
+ drawTriangle(a: Vector3, b: Vector3, c: Vector3, color?: Color): void;
6984
+ /** Draw a line as a camera facing ribbon, unlit
6985
+ * @param {Vector3} posA
6986
+ * @param {Vector3} posB
6987
+ * @param {number} [width]
6988
+ * @param {Color} [color] */
6989
+ drawLine(posA: Vector3, posB: Vector3, width?: number, color?: Color): void;
6990
+ /** Draw a ribbon along a path, unlit and visible from both sides; width and color can change along it
6991
+ * - The texture runs along the length, u from the first point to the last
6992
+ * - A path that ends where it starts is a loop, and joins with no seam
6993
+ * @param {Array<Vector3>} points - Center line in order, at least two
6994
+ * @param {number|Array<number>} [width] - Full width, one for all or one per point
6995
+ * @param {TileInfo|TextureInfo} [tileInfo]
6996
+ * @param {Color|Array<Color>} [color] - One for all or one per point
6997
+ * @param {Vector3|Array<Vector3>} [side] - Direction across the ribbon, one for all or one per point, default faces the camera */
6998
+ drawRibbon(points: Array<Vector3>, width?: number | Array<number>, tileInfo?: TileInfo | TextureInfo, color?: Color | Array<Color>, side?: Vector3 | Array<Vector3>): void;
6999
+ /** Draw a disc that fades to transparent at the rim, unlit, for glows, puffs and sky dots
7000
+ * @param {Vector3} pos - Center
7001
+ * @param {number} [size] - Diameter
7002
+ * @param {Color} [color]
7003
+ * @param {Vector3} [normal] - Facing direction, faces the camera by default
7004
+ * @param {number} [sides] */
7005
+ drawSoftDisc(pos: Vector3, size?: number, color?: Color, normal?: Vector3, sides?: number): any;
7006
+ /** Draw a soft round shadow on the ground under something, much cheaper than a real shadow
7007
+ * - Draw it from onRenderTransparent or from a transparent object
7008
+ * @param {Vector3} pos - Position of the thing casting the shadow
7009
+ * @param {number} [size] - Diameter
7010
+ * @param {number|HeightMap|Function} [floorHeight] - Height of the ground, a HeightMap, or (x, z) => y to follow terrain
7011
+ * @param {Color} [color]
7012
+ * @param {number} [lift] - How far above the ground to draw, raise it if the shadow cuts into rough ground */
7013
+ drawSoftShadow(pos: Vector3, size?: number, floorHeight?: number | HeightMap | Function, color?: Color, lift?: number): any;
7014
+ }
7015
+ /**
7016
+ * Camera3D - Position, rotation and lens for the 3D view
7017
+ * - Looks down its -Z axis, rotation is vec3(pitch, yaw, roll)
7018
+ * @memberof Render3D
7019
+ */
7020
+ export class Camera3D {
7021
+ /** @property {Vector3} - World position */
7022
+ pos: Vector3;
7023
+ /** @property {Vector3} - Euler rotation, vec3(pitch, yaw, roll) in radians */
7024
+ rotation: Vector3;
7025
+ /** @property {number} - Vertical field of view in radians */
7026
+ fov: number;
7027
+ /** @property {number} - Near clip distance */
7028
+ near: number;
7029
+ /** @property {number} - Far clip distance, Infinity is allowed for a perspective view */
7030
+ far: number;
7031
+ /** @property {number} - Visible height in world units for an orthographic view, 0 is perspective */
7032
+ orthographic: number;
7033
+ /** @property {boolean} - Line the 3D camera up with the 2D camera, so 3D things at z=0 sit on the 2D sprites */
7034
+ align2D: boolean;
7035
+ /** Returns the camera's world transform
7036
+ * @return {Matrix4} */
7037
+ getMatrix(): Matrix4;
7038
+ /** Returns the view matrix, world to camera space
7039
+ * @return {Matrix4} */
7040
+ getViewMatrix(): Matrix4;
7041
+ /** Returns the projection matrix
7042
+ * @param {number} aspect - Width over height
7043
+ * @return {Matrix4} */
7044
+ getProjectionMatrix(aspect: number): Matrix4;
7045
+ /** Returns the direction the camera looks
7046
+ * @return {Vector3} */
7047
+ getForward(): Vector3;
7048
+ /** Returns the camera's right axis
7049
+ * @return {Vector3} */
7050
+ getRight(): Vector3;
7051
+ /** Returns the camera's up axis
7052
+ * @return {Vector3} */
7053
+ getUp(): Vector3;
7054
+ /** Point the camera at a target, sets pitch and yaw and clears roll
7055
+ * @param {Vector3} target */
7056
+ lookAt(target: Vector3): void;
7057
+ /** Put the camera on an orbit around a target, looking at it
7058
+ * @param {Vector3} target
7059
+ * @param {number} distance
7060
+ * @param {number} yaw - Radians around Y
7061
+ * @param {number} [pitch] - Radians above the horizon */
7062
+ orbit(target: Vector3, distance: number, yaw: number, pitch?: number): void;
7063
+ /** Chase a target from an offset, easing toward it, and look at it
7064
+ * @param {Vector3} target
7065
+ * @param {Vector3} offset - Where to sit relative to the target
7066
+ * @param {number} [percent] - How far to move toward the spot each call, 1 snaps */
7067
+ follow(target: Vector3, offset: Vector3, percent?: number): void;
7068
+ /** Line the 3D camera up with the 2D camera, called automatically when align2D is set
7069
+ * @param {number} [canvasHeight] - Defaults to the main canvas height */
7070
+ update2D(canvasHeight?: number): void;
7071
+ }
7072
+ /**
7073
+ * EngineObject3D - An EngineObject with a 3D transform and a mesh
7074
+ * - Set pos3D, rotation3D and scale3D instead of the 2D pos, size and angle
7075
+ * - Gets update, children, timers, destroy and renderOrder from EngineObject
7076
+ * - velocity3D is added to pos3D each frame, along with render3D.gravity and damping once it has a mass
7077
+ * - Objects face -Z, the same way the camera does, so lookAt turns them to face a point
7078
+ * - The 2D pos and velocity are still there but nothing draws them
7079
+ * - These inherited fields are 2D only and do nothing here: angle, angleVelocity, angleDamping,
7080
+ * additiveColor, drawSize, mirror, clampSpeed, friction and groundObject
7081
+ * - The inherited shader works here as in 2D, and with emissive at 1 its snippet does its own lighting
7082
+ * - Set sync2D for a 2D game with 3D looks, pos and angle then drive pos3D and rotation3D,
7083
+ * which is the one way those 2D fields reach a 3D object
7084
+ * - setCollision takes the same flags as in 2D, but the solid collision happens in 3D against size3D
7085
+ * - Its tile and raycast halves are 2D only so they default off here, and a child sits solid collision out
7086
+ * - A sync2D object collides in 2D instead, which needs the 2D size set as well as size3D
7087
+ * - setMesh swaps the mesh and frees the old one, for text and terrain that get built again
7088
+ * - addChild attaches the 3D transform, and pos3D becomes an offset from the parent
7089
+ * - The 2D offset arguments of addChild do nothing here, set the child's pos3D
7090
+ * @extends EngineObject
7091
+ * @memberof Render3D
7092
+ * @example
7093
+ * class Spinner extends EngineObject3D
7094
+ * {
7095
+ * constructor(pos) { super(pos, buildBox(), undefined, RED); }
7096
+ * update() { this.rotation3D.y += .02; }
7097
+ * }
7098
+ */
7099
+ export class EngineObject3D extends EngineObject {
7100
+ /** Create a 3D object and add it to the object list
7101
+ * @param {Vector3} [pos3D] - World space position
7102
+ * @param {Mesh} [mesh] - Mesh to draw, undefined draws nothing
7103
+ * @param {TileInfo|TextureInfo} [tileInfo] - Texture, mesh uvs map across the tile; a whole TextureInfo becomes the tile that covers it
7104
+ * @param {Color} [color] - Tint */
7105
+ constructor(pos3D?: Vector3, mesh?: Mesh, tileInfo?: TileInfo | TextureInfo, color?: Color);
7106
+ /** @property {Vector3} - World space position, local to the parent when attached to an EngineObject3D */
7107
+ pos3D: Vector3;
7108
+ /** @property {Vector3} - Rotation vec3(pitch, yaw, roll) in radians, local to the parent when attached to an EngineObject3D */
7109
+ rotation3D: Vector3;
7110
+ /** @property {Vector3} - Scale, local to the parent when attached to an EngineObject3D */
7111
+ scale3D: Vector3;
7112
+ /** @property {Vector3} - Added to pos3D each frame by the engine before update, like the 2D velocity, no super call needed;
7113
+ * damping and render3D.gravity act on it once the object has a mass */
7114
+ velocity3D: Vector3;
7115
+ /** @property {Vector3} - Added to rotation3D each frame by the engine before update, angleDamping is 2D only */
7116
+ angleVelocity3D: Vector3;
7117
+ /** @property {Mesh|undefined} - Mesh to draw
7118
+ * @type {Mesh|undefined} */
7119
+ mesh: Mesh | undefined;
7120
+ /** @property {Vector3} - Size for the collect and callback helpers, and of the sprite when there is a tileInfo
7121
+ * and no mesh; scale3D and any parent's scale grow it, so drawing and picking agree */
7122
+ size3D: Vector3;
7123
+ /** @property {number} - Diameter of a soft shadow drawn under the object on render3D.softShadowHeight, 0 for none;
7124
+ * scale3D and a parent's scale grow it, so set it once for the unscaled object */
7125
+ softShadow: number;
7126
+ /** @property {boolean} - A sprite stands on world up instead of tilting toward the camera */
7127
+ upright: boolean;
7128
+ /** @property {boolean} - Keep this object's texture pixels hard edged, for pixel art that should not blur or bleed */
7129
+ pixelated: boolean;
7130
+ /** @property {boolean} - Copy the 2D pos and angle into pos3D and rotation3D each frame, for 2D games with 3D looks;
7131
+ * set mass to use 2D physics, and pos3D.z stays yours to set or move with velocity3D.z */
7132
+ sync2D: boolean;
7133
+ /** @property {boolean} - Draw in the transparent stage, blended and sorted far to near with depth writes off; on for a sprite */
7134
+ transparent: boolean;
7135
+ /** @property {boolean} - Additive blending, in the transparent stage */
7136
+ additive: boolean;
7137
+ /** @property {number} - How much it lights itself: 0 is lit as normal, 1 is its own color with no shading, for
7138
+ * lamps and glowing things, between is partly self lit, and above 1 is brighter than its color, for bloom */
7139
+ emissive: number;
7140
+ /** @property {number} - Strength of the highlight where the sunlight reflects, 0 is none and 1 adds the sun's full color at its brightest; its size is fixed */
7141
+ specular: number;
7142
+ /** @property {boolean} - Draw into the shadow map when render3D.shadows is on; sprites and cut out textures cast their outline, additive objects never cast */
7143
+ castShadow: boolean;
7144
+ /** @property {boolean} - Collide as the sphere that fits size3D instead of as the size3D box, so it rolls around corners */
7145
+ collideAsSphere3D: boolean;
7146
+ /** @property {boolean} - Darkened by the shadow map when render3D.shadows is on */
7147
+ receiveShadow: boolean;
7148
+ /** @property {boolean|undefined} - Draw this object over the 2D scene, undefined uses render3D.renderAfter2D
7149
+ * @type {boolean|undefined} */
7150
+ renderAfter2D: boolean | undefined;
7151
+ /** Returns the world position
7152
+ * @return {Vector3} */
7153
+ getWorldPos3D(): Vector3;
7154
+ /** Returns the direction the object faces, its -Z axis in the world
7155
+ * @return {Vector3} */
7156
+ getForward3D(): Vector3;
7157
+ /** Returns the object's right axis in the world
7158
+ * @return {Vector3} */
7159
+ getRight3D(): Vector3;
7160
+ /** Returns the object's up axis in the world
7161
+ * @return {Vector3} */
7162
+ getUp3D(): Vector3;
7163
+ /** Returns the object's world transform, relative to the parent's when attached to an EngineObject3D
7164
+ * @return {Matrix4} */
7165
+ getMatrix(): Matrix4;
7166
+ /** Turn the object so its -Z axis points at a world space target, sets pitch and yaw and clears roll
7167
+ * @param {Vector3} target */
7168
+ lookAt(target: Vector3): void;
7169
+ /** Draw a different mesh and free the GPU buffer of the one it replaces
7170
+ * - For a mesh built again when something changes, like a score, a rebuilt terrain or a loaded model
7171
+ * - A mesh another object is still drawing is left alone, since builders are often shared
7172
+ * - Freeing one held somewhere else only costs it an upload, the points it was built from stay
7173
+ * @param {Mesh} [mesh] - The mesh to draw from now on, undefined to draw nothing
7174
+ * @return {Mesh|undefined} - The mesh passed in */
7175
+ setMesh(mesh?: Mesh): Mesh | undefined;
7176
+ /** Draw the object in 3D, called by the 3D pass with the draw state set from this object's flags, draws the mesh by default */
7177
+ render3D(): void;
7178
+ }
7179
+ /**
7180
+ * Mesh - A triangle strip with positions, normals, uvs and colors, uploaded once and drawn by matrix
7181
+ * - Build with addStrip, addQuad, combine or the shape builders, then render each frame
7182
+ * - Its back faces are skipped unless doubleSided is set, which the open builders like buildGrid do for you
7183
+ * - The GPU buffer is created lazily on first render and dropped by dispose, or freed once the mesh is garbage
7184
+ * collected, so dispose is only needed to free it right away, like for a mesh rebuilt often
7185
+ * @memberof Render3D
7186
+ * @example
7187
+ * const mesh = buildLathe([[0, -1], [1, 0], [0, 1]], 4); // octahedron
7188
+ * mesh.render(buildMatrix(vec3(0, 1, 0)), undefined, RED);
7189
+ */
7190
+ export class Mesh {
7191
+ /** @property {Array<Vector3>} - Vertex positions in strip order
7192
+ * @type {Array<Vector3>} */
7193
+ points: Array<Vector3>;
7194
+ /** @property {Array<Vector3>} - Vertex normals
7195
+ * @type {Array<Vector3>} */
7196
+ normals: Array<Vector3>;
7197
+ /** @property {Array<Vector2>} - Vertex texture coords, 0-1 across the tile
7198
+ * @type {Array<Vector2>} */
7199
+ uvs: Array<Vector2>;
7200
+ /** @property {Array<Color>} - Vertex colors
7201
+ * @type {Array<Color>} */
7202
+ colors: Array<Color>;
7203
+ /** @property {WebGLBuffer|undefined} - GPU buffer, created by upload
7204
+ * @type {WebGLBuffer|undefined} */
7205
+ buffer: WebGLBuffer | undefined;
7206
+ /** @property {number} - Vertices in the GPU buffer */
7207
+ bufferCount: number;
7208
+ /** @property {boolean} - The mesh changed and needs uploading again, set it yourself if you edit the arrays */
7209
+ dirty: boolean;
7210
+ /** @property {boolean|undefined} - Draw every use of this mesh in the opaque stage as one instanced call, undefined follows render3D.instancing
7211
+ * @type {boolean|undefined} */
7212
+ instanced: boolean | undefined;
7213
+ /** @property {boolean} - Draw both sides, each lit as the side that is seen; off skips the faces pointing away,
7214
+ * which is faster and right for closed shapes, the open builders like buildGrid and buildRibbon turn it on */
7215
+ doubleSided: boolean;
7216
+ instanceCount: number;
7217
+ instanceData: any;
7218
+ /** @property {number} - Bounding sphere radius around the origin, for culling and picking, computed by upload */
7219
+ radius: number;
7220
+ contextGeneration: number;
7221
+ /** Number of vertices in the mesh
7222
+ * @return {number} */
7223
+ get vertexCount(): number;
7224
+ /** Add a triangle strip, joined to the previous one by invisible flat triangles so one mesh holds many strips
7225
+ * - Strip order: the first three points make a triangle, then each point makes another with the two before it
7226
+ * - List the first three points counter clockwise as seen from the front, or the face points away
7227
+ * and may vanish when back faces are culled
7228
+ * @param {Array<Vector3>} points - Strip order
7229
+ * @param {Vector3|Array<Vector3>} [normals] - One for all or one per point, default up
7230
+ * @param {Vector2|Array<Vector2>} [uvs] - One for all or one per point, default zero
7231
+ * @param {Color|Array<Color>} [colors] - One for all or one per point, default white
7232
+ * @return {Mesh} */
7233
+ addStrip(points: Array<Vector3>, normals?: Vector3 | Array<Vector3>, uvs?: Vector2 | Array<Vector2>, colors?: Color | Array<Color>): Mesh;
7234
+ /** Add a flat quad from four corners in loop order, counter clockwise seen from the front, a is the top left of the texture
7235
+ * @param {Vector3} a
7236
+ * @param {Vector3} b
7237
+ * @param {Vector3} c
7238
+ * @param {Vector3} d
7239
+ * @param {Color|Array<Color>} [color] - One for all or one per corner
7240
+ * @param {Array<Vector2>} [uvs] - One per corner, default across the tile
7241
+ * @return {Mesh} */
7242
+ addQuad(a: Vector3, b: Vector3, c: Vector3, d: Vector3, color?: Color | Array<Color>, uvs?: Array<Vector2>): Mesh;
7243
+ /** Append another mesh transformed by a matrix, for building one shape out of several
7244
+ * @param {Mesh} mesh
7245
+ * @param {Matrix4|Vector3} [matrix] - Transform, or just a position to move it to
7246
+ * @param {Color} [color] - Multiplies the appended vertex colors
7247
+ * @return {Mesh} */
7248
+ combine(mesh: Mesh, matrix?: Matrix4 | Vector3, color?: Color): Mesh;
7249
+ /** Scale every uv, so a whole texture repeats across the mesh when its TextureInfo wraps
7250
+ * @param {Vector2|number} scale - Repeats across and up, a number for both
7251
+ * @return {Mesh} */
7252
+ scaleUVs(scale: Vector2 | number): Mesh;
7253
+ /** Move, turn or scale every vertex in place, normals follow along
7254
+ * @param {Matrix4|Vector3} matrix - Transform, or just an offset to move by
7255
+ * @return {Mesh} */
7256
+ transform(matrix: Matrix4 | Vector3): Mesh;
7257
+ /** Turn the mesh inside out so it is lit and drawn from within, for rooms and domes
7258
+ * @return {Mesh} */
7259
+ flipNormals(): Mesh;
7260
+ /** Set every vertex color
7261
+ * @param {Color} color
7262
+ * @return {Mesh} */
7263
+ setColor(color: Color): Mesh;
7264
+ /** Measure the axis aligned box around the vertices
7265
+ * @return {{min: Vector3, max: Vector3}} */
7266
+ getBounds(): {
7267
+ min: Vector3;
7268
+ max: Vector3;
7269
+ };
7270
+ /** Move the mesh so the center of its bounds is on the origin
7271
+ * @return {Mesh} */
7272
+ center(): Mesh;
7273
+ /** Scale the mesh evenly so its largest extent is a size, for loaded models of unknown units
7274
+ * @param {number} [size]
7275
+ * @return {Mesh} */
7276
+ fit(size?: number): Mesh;
7277
+ /** Measure the bounding sphere around the origin into radius, called by upload
7278
+ * @return {number} */
7279
+ computeRadius(): number;
7280
+ /** Derive normals from the strip's triangles
7281
+ * @param {boolean} [smooth] - Round the lighting across faces instead of giving each face a hard edge
7282
+ * @return {Mesh} */
7283
+ computeNormals(smooth?: boolean): Mesh;
7284
+ /** Pack the vertices and create the GPU buffer, called automatically by render
7285
+ * @return {Mesh} */
7286
+ upload(): Mesh;
7287
+ /** Draw the mesh with the current draw state, batched with its other uses in the opaque stage
7288
+ * @param {Matrix4|Vector3} [matrix] - Object transform, or just a position to draw it at
7289
+ * @param {TileInfo|TextureInfo} [tileInfo] - Texture, mesh uvs map across the tile or the whole texture
7290
+ * @param {Color} [color] - Tint */
7291
+ render(matrix?: Matrix4 | Vector3, tileInfo?: TileInfo | TextureInfo, color?: Color): void;
7292
+ /** Delete the GPU buffer now, the CPU arrays stay so the mesh can be rendered again
7293
+ * - Optional, the buffer is freed anyway once the mesh is garbage collected, this frees it right away */
7294
+ dispose(): void;
7295
+ }
7296
+ /**
7297
+ * Spin a flat outline around the Y axis to make a round shape, like a vase or a wheel
7298
+ * - profile is [[radius, y], ...] from bottom to top
7299
+ * - A profile that ends where it starts makes a closed ring like a donut
7300
+ * - An end left open, with a radius and no cap, makes the mesh doubleSided so its inside shows
7301
+ * @param {Array<Array<number>>} profile
7302
+ * @param {number} [sides] - Around the axis
7303
+ * @param {boolean} [smooth] - Defaults to render3D.smoothShading
7304
+ * @param {boolean} [capped] - Close the ends that have a radius with flat discs
7305
+ * @return {Mesh}
7306
+ * @memberof Render3D
7307
+ * @example
7308
+ * const vase = buildLathe([[0, -1], [.8, -.3], [.9, .2], [.4, .6], [0, 1]], 12);
7309
+ */
7310
+ export function buildLathe(profile: Array<Array<number>>, sides?: number, smooth?: boolean, capped?: boolean): Mesh;
7311
+ /**
7312
+ * Build a cylinder standing on the Y axis, centered on the origin
7313
+ * @param {number} [size] - Diameter
7314
+ * @param {number} [height]
7315
+ * @param {number} [sides] - Around
7316
+ * @param {boolean} [smooth] - Defaults to render3D.smoothShading
7317
+ * @param {boolean} [capped] - Close the ends
7318
+ * @return {Mesh}
7319
+ * @memberof Render3D
7320
+ */
7321
+ export function buildCylinder(size?: number, height?: number, sides?: number, smooth?: boolean, capped?: boolean): Mesh;
7322
+ /**
7323
+ * Build a sphere centered on the origin
7324
+ * @param {number} [size] - Diameter
7325
+ * @param {number} [sides] - Around
7326
+ * @param {number} [rings] - Top to bottom
7327
+ * @param {boolean} [smooth] - Defaults to render3D.smoothShading
7328
+ * @return {Mesh}
7329
+ * @memberof Render3D
7330
+ */
7331
+ export function buildSphere(size?: number, sides?: number, rings?: number, smooth?: boolean): Mesh;
7332
+ /**
7333
+ * Build a cone standing on the Y axis, centered on the origin, the point up
7334
+ * @param {number} [size] - Diameter of the base
7335
+ * @param {number} [height]
7336
+ * @param {number} [sides] - Around
7337
+ * @param {boolean} [smooth] - Defaults to render3D.smoothShading
7338
+ * @param {boolean} [capped] - Close the base
7339
+ * @return {Mesh}
7340
+ * @memberof Render3D
7341
+ */
7342
+ export function buildCone(size?: number, height?: number, sides?: number, smooth?: boolean, capped?: boolean): Mesh;
7343
+ /**
7344
+ * Build a capsule standing on the Y axis, centered on the origin: a cylinder with a half sphere on each end
7345
+ * @param {number} [size] - Diameter
7346
+ * @param {number} [height] - Total height including the rounded ends, at least the size
7347
+ * @param {number} [sides] - Around
7348
+ * @param {number} [rings] - On each end
7349
+ * @param {boolean} [smooth] - Defaults to render3D.smoothShading
7350
+ * @return {Mesh}
7351
+ * @memberof Render3D
7352
+ */
7353
+ export function buildCapsule(size?: number, height?: number, sides?: number, rings?: number, smooth?: boolean): Mesh;
7354
+ /**
7355
+ * Build a donut lying flat around the Y axis
7356
+ * @param {number} [size] - Diameter of the whole donut, outside edge to outside edge
7357
+ * @param {number} [tubeSize] - Diameter of the tube
7358
+ * @param {number} [sides] - Around the ring
7359
+ * @param {number} [tubeSides] - Around the tube
7360
+ * @param {boolean} [smooth] - Defaults to render3D.smoothShading
7361
+ * @return {Mesh}
7362
+ * @memberof Render3D
7363
+ */
7364
+ export function buildTorus(size?: number, tubeSize?: number, sides?: number, tubeSides?: number, smooth?: boolean): Mesh;
7365
+ /**
7366
+ * Build a box centered on the origin, six flat faces with uvs covering each face
7367
+ * @param {Vector3|number} [size] - Full size, a number for a cube
7368
+ * @return {Mesh}
7369
+ * @memberof Render3D
7370
+ */
7371
+ export function buildBox(size?: Vector3 | number): Mesh;
7372
+ /**
7373
+ * Build a heightfield grid in the XZ plane centered on the origin
7374
+ * - smooth rounds the lighting across cells and colors each corner
7375
+ * - flat lights and colors each cell on its own, so a checkerboard stays crisp
7376
+ * - doubleSided, a sheet seen from both sides; turn it off for ground only ever seen from above
7377
+ * - One cell is a plain square, render3D.planeMesh and planeMeshDoubleSided are shared ones
7378
+ * @param {Vector2} [size] - World size along X and Z
7379
+ * @param {Vector2|number} [segments] - Cells along X and Z, a number for both
7380
+ * @param {Color|Function} [color] - One Color for the whole grid, or (x, z) => Color
7381
+ * @param {Function} [heightFunction] - (x, z) => y, default flat
7382
+ * @param {boolean} [smooth] - Defaults to render3D.smoothShading
7383
+ * @return {Mesh}
7384
+ * @memberof Render3D
7385
+ * @example
7386
+ * const ground = buildGrid(vec2(20), 10, (x, z)=> (floor(x / 2) + floor(z / 2)) & 1 ? GRAY : WHITE); // 2 unit checks
7387
+ */
7388
+ export function buildGrid(size?: Vector2, segments?: Vector2 | number, color?: Color | Function, heightFunction?: Function, smooth?: boolean): Mesh;
7389
+ /**
7390
+ * Build a lit ribbon along a path, for roads, tracks and walls
7391
+ * - Each segment is a flat quad, the sides are across the path in the plane of the up vector
7392
+ * - doubleSided, so it is seen and lit from below as well
7393
+ * @param {Array<Vector3>} points - Center line in order
7394
+ * @param {number|Array<number>} [width] - Full width, one for all or one per point
7395
+ * @param {Color|Array<Color>} [color] - One for all or one per point
7396
+ * @param {boolean} [closed] - Join the last point back to the first
7397
+ * @param {Vector3} [up] - Which way the ribbon faces
7398
+ * @return {Mesh}
7399
+ * @memberof Render3D
7400
+ * @example
7401
+ * const road = buildRibbon(trackPoints, 8, GRAY, true); // a loop of road
7402
+ */
7403
+ export function buildRibbon(points: Array<Vector3>, width?: number | Array<number>, color?: Color | Array<Color>, closed?: boolean, up?: Vector3): Mesh;
7404
+ /**
7405
+ * Build a hull from a row of diamond shaped slices along Z, for ships, planes and cars
7406
+ * - Each slice is [z, width, top, bottom, sideHeight]
7407
+ * - sideHeight is 0 to 1 and puts the side corners between the bottom and the top
7408
+ * - List the slices nose first, with the nose at the largest z
7409
+ * @param {Array<Array<number>>} stations
7410
+ * @return {Mesh}
7411
+ * @memberof Render3D
7412
+ * @example
7413
+ * const hull = buildLoft([[1.2, .4, .2, -.1], [0, 1.4, .5, -.4], [-1, 1, .3, -.3]]);
7414
+ */
7415
+ export function buildLoft(stations: Array<Array<number>>): Mesh;
7416
+ /**
7417
+ * Build a sky dome: a sphere colored by direction, wound to be seen from inside
7418
+ * - set it as render3D.sky and the pass draws it around the camera behind everything
7419
+ * @param {Color} [topColor] - Straight up
7420
+ * @param {Color} [horizonColor] - Level with the camera
7421
+ * @param {Color} [bottomColor] - Straight down, what a camera looking at the ground sees past its edge; defaults to the horizon color
7422
+ * @param {number} [sides] - Around
7423
+ * @param {number} [rings] - Top to bottom
7424
+ * @return {Mesh}
7425
+ * @memberof Render3D
7426
+ */
7427
+ export function buildSky(topColor?: Color, horizonColor?: Color, bottomColor?: Color, sides?: number, rings?: number): Mesh;
7428
+ /**
7429
+ * Turn a sprite into a 3D block model by giving its pixels thickness
7430
+ * - A pixel counts as solid when it is more than half opaque
7431
+ * - Each pixel keeps its own color, so white art takes the object's tint
7432
+ * - Runs of matching pixels merge into one face, and side walls appear only at the sprite's edges
7433
+ * - A texture's pixels are read once and kept, so redrawing a canvas texture will not change what this builds
7434
+ * - Pixels can also be an array of rows, each a Color, a truthy value for white, or a falsy value for empty
7435
+ * @param {TileInfo|Array<Array<Color|number|boolean>>} pixels - A tile from a loaded texture, or rows of pixels,
7436
+ * each a Color (empty when see through), a truthy value for white or a falsy value for empty
7437
+ * @param {Vector2} [size] - World width and height of the whole tile, centered like buildBox
7438
+ * @param {number} [depth] - Thickness along Z
7439
+ * @return {Mesh}
7440
+ * @memberof Render3D
7441
+ * @example
7442
+ * new EngineObject3D(vec3(), buildExtrude(tile(3, 16), vec2(2), .5)); // a chunky version of tile 3
7443
+ */
7444
+ export function buildExtrude(pixels: TileInfo | Array<Array<Color | number | boolean>>, size?: Vector2, depth?: number): Mesh;
7445
+ /**
7446
+ * Build a mesh of extruded text from an image font, the engine font by default so it needs no assets
7447
+ * - Each glyph is extruded once per font and reused, the block is centered and faces +Z
7448
+ * - Newlines stack downward, spaced a little wider than the character height so the sides do not collide
7449
+ * - Every call builds a new mesh, dispose the old one when text changes often
7450
+ * - Glyphs are white in the engine font, so the object's color tints the text
7451
+ * @param {string|number} text
7452
+ * @param {number} [size] - Character height in world units
7453
+ * @param {number} [depth] - Thickness along Z
7454
+ * @param {ImageFont} [font] - Defaults to engineImageFont
7455
+ * @return {Mesh}
7456
+ * @memberof Render3D
7457
+ * @example
7458
+ * new EngineObject3D(vec3(0, 2, 0), buildText3D('HELLO'), undefined, YELLOW);
7459
+ */
7460
+ export function buildText3D(text: string | number, size?: number, depth?: number, font?: ImageFont): Mesh;
7461
+ /**
7462
+ * HeightMap - Terrain built from a grid of heights, with a mesh, a height lookup and a raycast
7463
+ * - heights is a 2D array [row][column] of 0 to 1 values
7464
+ * - Row 0 is the far edge at -Z and column 0 is the left edge at -X
7465
+ * - It can be an image instead, where the red channel is the height
7466
+ * - colors is an optional 2D array of Colors or an image, sampled per vertex
7467
+ * - images are read through a canvas, so they must be same origin or loaded with crossOrigin set
7468
+ * @memberof Render3D
7469
+ * @example
7470
+ * const terrain = new HeightMap(heightImage, vec2(100, 100), 10, colorImage);
7471
+ * new EngineObject3D(vec3(), terrain.buildMesh());
7472
+ * const y = terrain.getHeight(x, z); // stand things on it
7473
+ */
7474
+ export class HeightMap {
7475
+ /** Create a height map from an array or an image
7476
+ * @param {Array<Array<number>>|HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|TextureInfo} heights
7477
+ * @param {Vector2} [size] - World size along X and Z
7478
+ * @param {number} [height] - World height of a full value
7479
+ * @param {Array<Array<Color>>|HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|TextureInfo} [colors] */
7480
+ constructor(heights: Array<Array<number>> | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | TextureInfo, size?: Vector2, height?: number, colors?: Array<Array<Color>> | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | TextureInfo);
7481
+ /** @property {Array<Array<number>>} - Heights 0-1 as [row][column], rows along Z */
7482
+ heights: number[][];
7483
+ /** @property {Array<Array<Color>>|undefined} - Vertex colors as [row][column], undefined for white
7484
+ * @type {Array<Array<Color>>|undefined} */
7485
+ colors: Array<Array<Color>> | undefined;
7486
+ /** @property {Vector2} - World size along X and Z */
7487
+ size: Vector2;
7488
+ /** @property {number} - World height of a full value */
7489
+ height: number;
7490
+ /** Number of rows, along Z
7491
+ * @return {number} */
7492
+ get rows(): number;
7493
+ /** Number of columns, along X
7494
+ * @return {number} */
7495
+ get columns(): number;
7496
+ /** World height at a position, exactly the height of the mesh buildMesh draws there, clamped at the edges
7497
+ * @param {number|Vector3} x - X, or a position to take X and Z from
7498
+ * @param {number} [z]
7499
+ * @return {number} */
7500
+ getHeight(x: number | Vector3, z?: number): number;
7501
+ /** Surface normal at a position, from the slope across a sample
7502
+ * @param {number|Vector3} x - X, or a position to take X and Z from
7503
+ * @param {number} [z]
7504
+ * @return {Vector3} */
7505
+ getNormal(x: number | Vector3, z?: number): Vector3;
7506
+ /** Color of the nearest sample to a position, white when there are no colors
7507
+ * @param {number|Vector3} x - X, or a position to take X and Z from
7508
+ * @param {number} [z]
7509
+ * @return {Color} */
7510
+ getColor(x: number | Vector3, z?: number): Color;
7511
+ /** Distance along a ray to where it crosses the terrain surface, or undefined for a miss
7512
+ * - Steps along the ray half a cell at a time, then narrows in on the exact spot
7513
+ * - A ray that starts under the ground crosses on its way out, so the hit is still on the surface
7514
+ * @param {Ray3D} ray - From screenToRay, or any ray
7515
+ * @return {number|undefined} */
7516
+ raycast(ray: Ray3D): number | undefined;
7517
+ /** Build the terrain mesh, one vertex per sample, centered on the origin
7518
+ * @param {boolean} [smooth] - Defaults to render3D.smoothShading
7519
+ * @return {Mesh} */
7520
+ buildMesh(smooth?: boolean): Mesh;
7521
+ }
7522
+ /**
7523
+ * Light3D - A light that is an EngineObject3D, so it can move, follow a parent or be destroyed like anything else
7524
+ * - A point light: it lights what is near it and fades out by its radius, DirectionalLight3D shines from far away
7525
+ * - Only the sun, render3D.sunDirection, casts shadows and makes highlights, these light without either
7526
+ * - Only the 8 lights nearest the camera are used each frame
7527
+ * - radius is where the light fades out, and it fades fast, so a small radius wants a higher intensity
7528
+ * - intensity multiplies the color, above 1 for a light brighter than white
7529
+ * - radius is a world distance, so scale3D does not change it
7530
+ * - An alpha, an intensity or a radius of 0 switches it off, and a light that is off takes none of those slots
7531
+ * - Draws nothing itself, add a glow with drawSoftDisc or a small emissive mesh if it should be seen
7532
+ * @extends EngineObject3D
7533
+ * @memberof Render3D
7534
+ * @example
7535
+ * const torch = new Light3D(vec3(0, 3, 0), 10, hsl(.1, 1, .65));
7536
+ */
7537
+ export class Light3D extends EngineObject3D {
7538
+ /** Create a point light
7539
+ * @param {Vector3} [pos3D] - Where it is
7540
+ * @param {number} [radius] - Distance where the light fades to nothing
7541
+ * @param {Color} [color] - Light color, its alpha fades it
7542
+ * @param {number} [intensity] - Brightness, multiplies the color, above 1 is brighter than white */
7543
+ constructor(pos3D?: Vector3, radius?: number, color?: Color, intensity?: number);
7544
+ /** @property {number} - Distance where the light fades to nothing */
7545
+ radius: number;
7546
+ /** @property {number} - Brightness, multiplies the color, above 1 is brighter than white */
7547
+ intensity: number;
7548
+ /** @property {boolean} - Shine from far away, from its position toward the origin, instead of out from its
7549
+ * position with a falloff; DirectionalLight3D sets it */
7550
+ directional: boolean;
7551
+ }
7552
+ /**
7553
+ * DirectionalLight3D - A Light3D that shines from far away with no falloff, like sunlight
7554
+ * - It shines from its position toward the origin, like a three.js DirectionalLight: only the direction to it
7555
+ * counts, so moving it or its parent swings the light around; parent it to a sun in the sky and it follows
7556
+ * - It cannot sit on the origin, since that leaves no direction
7557
+ * - Like every Light3D it casts no shadow and makes no highlight, only the sun, render3D.sunDirection, does
7558
+ * @extends Light3D
7559
+ * @memberof Render3D
7560
+ * @example
7561
+ * const fill = new DirectionalLight3D(vec3(-1, 1, 1), hsl(.6, .5, .3)); // from the back left and above
7562
+ */
7563
+ export class DirectionalLight3D extends Light3D {
7564
+ /** Create a directional light
7565
+ * @param {Vector3} [pos3D] - Where it shines from, toward the origin
7566
+ * @param {Color} [color] - Light color, its alpha fades it
7567
+ * @param {number} [intensity] - Brightness, multiplies the color, above 1 is brighter than white */
7568
+ constructor(pos3D?: Vector3, color?: Color, intensity?: number);
7569
+ }
7570
+ /**
7571
+ * CameraControl3D - Drag to turn the camera around a point, roll the wheel to zoom
7572
+ * - An EngineObject3D, so move its pos3D to follow something, or parent it to an object
7573
+ * - Destroy it to hand the camera back, and it stops driving the camera
7574
+ * - Set persistent to keep it when engineObjectsDestroy clears out a level
7575
+ * - Every part of it is a field, so a game can change the buttons, speeds and limits
7576
+ * @extends EngineObject3D
7577
+ * @memberof Render3D
7578
+ * @example
7579
+ * new CameraControl3D(vec3(0, 1, 0), 15); // look at a point from 15 units away
7580
+ */
7581
+ export class CameraControl3D extends EngineObject3D {
7582
+ /** Create a camera control, it drives render3D.camera every frame
7583
+ * @param {Vector3} [target] - The point to look at, its pos3D
7584
+ * @param {number} [distance] - How far the camera sits from the target
7585
+ * @param {number} [pitch] - Angle above the horizon, PI/2 looks straight down
7586
+ * @param {number} [idleSpin] - Turned each frame while not dragging, 0 holds still */
7587
+ constructor(target?: Vector3, distance?: number, pitch?: number, idleSpin?: number);
7588
+ /** @property {number} - How far the camera sits from the target */
7589
+ distance: number;
7590
+ /** @property {number} - Angle above the horizon */
7591
+ pitch: number;
7592
+ /** @property {number} - Turned each frame while not dragging */
7593
+ idleSpin: number;
7594
+ /** @property {number} - Angle around the target, dragging changes it */
7595
+ yaw: number;
7596
+ /** @property {number} - Mouse button that turns the camera, 0 is left and 2 is right */
7597
+ dragButton: number;
7598
+ /** @property {number} - How far dragging a pixel turns the camera */
7599
+ dragSpeed: number;
7600
+ /** @property {number} - How much one wheel notch zooms, 0 turns zooming off */
7601
+ zoomSpeed: number;
7602
+ /** @property {Vector2} - Closest and furthest the wheel can zoom to */
7603
+ zoomRange: Vector2;
7604
+ /** @property {Vector2} - Lowest and highest pitch, so it cannot tip over the top */
7605
+ pitchRange: Vector2;
7606
+ }
7607
+ /**
7608
+ * FirstPersonCamera3D - Look around with the mouse and move with the keys, with the camera at its position
7609
+ * - Click to capture the mouse so looking needs no button held, Esc lets it go; holding the button looks too, for touch
7610
+ * - WASD or the arrow keys walk level, or move the way it looks when fly is set
7611
+ * - An EngineObject3D that moves by velocity3D, so give it a size3D and call setCollision to walk into solid
7612
+ * objects instead of through them; walking keeps velocity3D.y, so render3D.gravity can pull it down
7613
+ * - Starts from wherever render3D.camera is, so it can take over from another camera without a jump
7614
+ * - Destroy it to hand the camera back
7615
+ * @extends EngineObject3D
7616
+ * @memberof Render3D
7617
+ * @example
7618
+ * const player = new FirstPersonCamera3D(vec3(0, 1.5, 5));
7619
+ * player.size3D = vec3(1); // bump into solid objects
7620
+ * player.collideAsSphere3D = true;
7621
+ * player.setCollision();
7622
+ */
7623
+ export class FirstPersonCamera3D extends EngineObject3D {
7624
+ /** Create a first person camera, it drives render3D.camera every frame
7625
+ * @param {Vector3} [pos3D] - Where the eye is, defaults to where the camera is now
7626
+ * @param {number} [yaw] - Radians around Y, defaults to the camera's
7627
+ * @param {number} [pitch] - Radians up from level, defaults to the camera's */
7628
+ constructor(pos3D?: Vector3, yaw?: number, pitch?: number);
7629
+ /** @property {number} - Angle around Y, the mouse turns it */
7630
+ yaw: number;
7631
+ /** @property {number} - Angle up from level, the mouse tilts it */
7632
+ pitch: number;
7633
+ /** @property {number} - World units per frame at full speed */
7634
+ moveSpeed: number;
7635
+ /** @property {number} - How far a pixel of mouse movement turns the view */
7636
+ lookSpeed: number;
7637
+ /** @property {Vector2} - Lowest and highest pitch */
7638
+ pitchRange: Vector2;
7639
+ /** @property {boolean} - Move the way it looks, up and down included, instead of walking level */
7640
+ fly: boolean;
7641
+ /** @property {boolean} - Capture the mouse on a click, so looking needs no button held */
7642
+ lockPointer: boolean;
7643
+ }
7644
+ /**
7645
+ * ParticleEmitter3D - Spawns camera facing particles, the 3D twin of ParticleEmitter
7646
+ * - Each particle is a flat square facing the camera, with a soft round dot when no tile is given
7647
+ * - Set trailTime to draw each particle as a streak along where it has been, for sparks
7648
+ * - Set angleSpeed to tumble them in the camera plane, which the 2D emitter takes as an argument
7649
+ * - Particles shoot out along the emitter's own up axis, turned by rotation3D
7650
+ * - emitConeAngle spreads them, PI sprays in every direction
7651
+ * - Speeds are per frame and sizes are world units, the same as the 2D emitter
7652
+ * - scale3D, its own or a parent's, grows the whole effect: the spawn area, the sizes, the speed and the fall
7653
+ * - gravity here is its own number added to velocity y each frame: it is neither the engine's 2D
7654
+ * gravity nor render3D.gravity, so an effect keeps its own fall wherever it is used
7655
+ * - An emitter with an emitTime destroys itself once its last particle is gone, like the 2D emitter
7656
+ * @extends EngineObject3D
7657
+ * @memberof Render3D
7658
+ * @example
7659
+ * // fire: a stream upward, yellow fading to transparent red, additive
7660
+ * new ParticleEmitter3D(vec3(), .5, 0, 100, .3, undefined, hsl(.12, 1, .6), hsl(.08, 1, .5), hsl(0, 1, .5, 0), hsl(0, 1, .25, 0), 1, .5, 1.5, .05, .95, 0, .3, .2, true);
7661
+ */
7662
+ export class ParticleEmitter3D extends EngineObject3D {
7663
+ /** Create a particle emitter
7664
+ * @param {Vector3} [pos3D] - World space position of the emitter
7665
+ * @param {number|Vector3} [emitSize] - Spawn area, a number for a sphere diameter or a vec3 for a box
7666
+ * @param {number} [emitTime] - How long to keep emitting, 0 is forever
7667
+ * @param {number} [emitRate] - Particles per second, 0 does not emit
7668
+ * @param {number} [emitConeAngle] - Half angle around the emit direction, PI is every direction
7669
+ * @param {TileInfo|TextureInfo} [tileInfo] - Tile to render particles with, or a whole texture, undefined is untextured
7670
+ * @param {Color} [colorStartA] - Color at start of life, randomized between the start colors
7671
+ * @param {Color} [colorStartB]
7672
+ * @param {Color} [colorEndA] - Color at end of life, randomized between the end colors
7673
+ * @param {Color} [colorEndB]
7674
+ * @param {number} [particleTime] - How long particles live in seconds
7675
+ * @param {number} [sizeStart] - Particle size at start of life
7676
+ * @param {number} [sizeEnd] - Particle size at end of life
7677
+ * @param {number} [speed] - Spawn speed in world units per frame
7678
+ * @param {number} [damping] - Per frame velocity multiplier, 1 is none
7679
+ * @param {number} [gravity] - Per frame change to velocity y, negative pulls down; its own number,
7680
+ * not render3D.gravity, so the 2D emitter's gravityScale has no equivalent here
7681
+ * @param {number} [fadeRate] - Fraction of life spent fading, half in and half out
7682
+ * @param {number} [randomness] - Extra randomness applied to speed, size and life
7683
+ * @param {boolean} [additive] - Additive blending */
7684
+ constructor(pos3D?: Vector3, emitSize?: number | Vector3, emitTime?: number, emitRate?: number, emitConeAngle?: number, tileInfo?: TileInfo | TextureInfo, colorStartA?: Color, colorStartB?: Color, colorEndA?: Color, colorEndB?: Color, particleTime?: number, sizeStart?: number, sizeEnd?: number, speed?: number, damping?: number, gravity?: number, fadeRate?: number, randomness?: number, additive?: boolean);
7685
+ /** @property {number|Vector3} - Spawn area, a number for a sphere diameter or a vec3 for a box */
7686
+ emitSize: number | Vector3;
7687
+ /** @property {number} - How long to keep emitting, 0 is forever */
7688
+ emitTime: number;
7689
+ /** @property {number} - Particles per second, 0 does not emit */
7690
+ emitRate: number;
7691
+ /** @property {number} - Half angle around the emit direction, PI is every direction */
7692
+ emitConeAngle: number;
7693
+ /** @property {Color} - Color at start of life, randomized between the start colors */
7694
+ colorStartA: Color;
7695
+ /** @property {Color} - Color at start of life, randomized between the start colors */
7696
+ colorStartB: Color;
7697
+ /** @property {Color} - Color at end of life, randomized between the end colors */
7698
+ colorEndA: Color;
7699
+ /** @property {Color} - Color at end of life, randomized between the end colors */
7700
+ colorEndB: Color;
7701
+ /** @property {number} - How long particles live in seconds */
7702
+ particleTime: number;
7703
+ /** @property {number} - Particle size at start of life */
7704
+ sizeStart: number;
7705
+ /** @property {number} - Particle size at end of life */
7706
+ sizeEnd: number;
7707
+ /** @property {number} - Spawn speed in world units per frame */
7708
+ speed: number;
7709
+ /** @property {number} - Per frame change to velocity y, its own number and not render3D.gravity */
7710
+ gravity: number;
7711
+ /** @property {number} - Fraction of life spent fading, half in and half out */
7712
+ fadeRate: number;
7713
+ /** @property {number} - Extra randomness applied to speed, size and life */
7714
+ randomness: number;
7715
+ /** @property {number} - Seconds of each particle's path to draw as a ribbon behind it, 0 draws billboards */
7716
+ trailTime: number;
7717
+ /** @property {number} - Radians per frame each particle turns in the camera plane, either way; 0 is no spin */
7718
+ angleSpeed: number;
7719
+ /** @property {Array<Object>} - Live particles
7720
+ * @type {Array<Object>} */
7721
+ particles: Array<any>;
7722
+ emitTimeBuffer: number;
7723
+ worldPos3D: Vector3;
7724
+ /** Spawn one particle now */
7725
+ emitParticle(): void;
7726
+ /** Draw the particles, as flat squares or as streaks when trailTime is set
7727
+ * - The whole emitter sorts as one thing, its particles are not sorted against each other */
7728
+ render3D(): any;
7729
+ }
7730
+ /**
7731
+ * Trail3D - A ribbon through where the object has been, thinning and fading with age
7732
+ * - Records its world position each frame it moves, so parent it to something that moves or set pos3D yourself
7733
+ * - The samples are world space, so width is a world width and scale3D does nothing to the ribbon
7734
+ * - Drawn unlit in the transparent stage, dies down on its own once the object stops
7735
+ * @extends EngineObject3D
7736
+ * @memberof Render3D
7737
+ * @example
7738
+ * const trail = new Trail3D(vec3(), 1, .3, undefined, hsl(.08, 1, .5), hsl(0, 1, .5, 0), true);
7739
+ * ball.addChild(trail); // follows the ball
7740
+ */
7741
+ export class Trail3D extends EngineObject3D {
7742
+ /** Create a trail
7743
+ * @param {Vector3} [pos3D]
7744
+ * @param {number} [lifeTime] - Seconds the ribbon takes to thin and fade from head to tail,
7745
+ * Infinity keeps every sample at full width and never drops one, so it grows as long as the object moves
7746
+ * @param {number} [width] - Width at the head, it thins to nothing at the tail
7747
+ * @param {TileInfo|TextureInfo} [tileInfo] - Tile or whole texture stretched along the trail, undefined is untextured
7748
+ * @param {Color} [color] - Color at the head
7749
+ * @param {Color} [colorEnd] - Color at the tail
7750
+ * @param {boolean} [additive] - Additive blending */
7751
+ constructor(pos3D?: Vector3, lifeTime?: number, width?: number, tileInfo?: TileInfo | TextureInfo, color?: Color, colorEnd?: Color, additive?: boolean);
7752
+ finishing: boolean;
7753
+ /** @property {number} - Seconds the ribbon takes to thin and fade from head to tail, Infinity never drops a sample */
7754
+ lifeTime: number;
7755
+ /** @property {number} - Width at the head */
7756
+ width: number;
7757
+ /** @property {Color} - Color at the tail */
7758
+ colorEnd: Color;
7759
+ /** @property {Vector3|undefined} - Direction across the ribbon, recorded with each sample, undefined faces the camera
7760
+ * @type {Vector3|undefined} */
7761
+ side: Vector3 | undefined;
7762
+ /** @property {Array<Object>} - Recorded samples, oldest first
7763
+ * @type {Array<Object>} */
7764
+ samples: Array<any>;
7765
+ /** Forget the trail so far, for when the object teleports */
7766
+ clear(): void;
7767
+ worldPos3D: Vector3;
7768
+ }
7769
+ /**
7770
+ * Collect the EngineObject3D objects whose boxes overlap a box, sizes are full sizes
7771
+ * - Boxes are axis aligned around the world position, rotation3D is ignored; lights, emitters and trails have no size
7772
+ * @param {Vector3} pos - Center of the box
7773
+ * @param {Vector3|number} size - Full size of the box, a number for a cube
7774
+ * @param {Array<EngineObject>} [objects] - Defaults to every object
7775
+ * @return {Array<EngineObject3D>}
7776
+ * @memberof Render3D
7777
+ */
7778
+ export function engineObjectsCollect3D(pos: Vector3, size: Vector3 | number, objects?: Array<EngineObject>): Array<EngineObject3D>;
7779
+ /**
7780
+ * Call a function for each EngineObject3D whose box overlaps a box
7781
+ * @param {Vector3} pos - Center of the box
7782
+ * @param {Vector3|number} size - Full size of the box, a number for a cube
7783
+ * @param {Function} callback
7784
+ * @param {Array<EngineObject>} [objects] - Defaults to every object
7785
+ * @memberof Render3D
7786
+ */
7787
+ export function engineObjectsCallback3D(pos: Vector3, size: Vector3 | number, callback: Function, objects?: Array<EngineObject>): void;
7788
+ /**
7789
+ * Collect every EngineObject3D a ray passes through, nearest first, the 3D twin of engineObjectsRaycast
7790
+ * - The ray has no end, so everything along it counts however far away it is
7791
+ * - Use render3D.pick for the nearest one on its own, with the distance to it
7792
+ * @param {Ray3D} ray - From render3D.screenToRay, or any ray
7793
+ * @param {Array<EngineObject>} [objects] - Defaults to every object; only those with a mesh or a sprite count
7794
+ * @return {Array<EngineObject3D>}
7795
+ * @memberof Render3D
7796
+ */
7797
+ export function engineObjectsRaycast3D(ray: Ray3D, objects?: Array<EngineObject>): Array<EngineObject3D>;
7798
+ /**
7799
+ * Parse Wavefront OBJ text into a Mesh
7800
+ * - Reads v, vt, vn and f lines with convex polygons of any size, materials and groups are ignored
7801
+ * - Normals come from the file when every corner of a face has one, otherwise from the face
7802
+ * - Use mesh.center() and mesh.fit(size) to bring a model of unknown units to the origin
7803
+ * - Back faces are skipped like any mesh, set doubleSided for a model with open walls or single sided parts
7804
+ * @param {string} text
7805
+ * @param {boolean} [smooth] - Compute smooth normals when the file has none, defaults to render3D.smoothShading
7806
+ * @return {Mesh}
7807
+ * @memberof Render3D
7808
+ * @example
7809
+ * new EngineObject3D(vec3(), parseOBJ(objText).center().fit(4));
7810
+ */
7811
+ export function parseOBJ(text: string, smooth?: boolean): Mesh;
7812
+ /**
7813
+ * Fetch and parse an OBJ file
7814
+ * @param {string} url
7815
+ * @param {boolean} [smooth] - Compute smooth normals when the file has none, defaults to render3D.smoothShading
7816
+ * @return {Promise<Mesh>}
7817
+ * @memberof Render3D
7818
+ * @example
7819
+ * const mesh = await loadOBJ('ship.obj'); // in an async gameInit
7820
+ */
7821
+ export function loadOBJ(url: string, smooth?: boolean): Promise<Mesh>;
7822
+ /** Draw a debug wireframe box
7823
+ * @param {Vector3} pos - Center
7824
+ * @param {Vector3|number} [size] - Full size, a number for a cube
7825
+ * @param {Color} [color]
7826
+ * @param {number} [time] - How long to show it, 0 is one frame
7827
+ * @param {Vector3} [rotation] - vec3(pitch, yaw, roll)
7828
+ * @memberof Render3D */
7829
+ export function debugBox3D(pos: Vector3, size?: Vector3 | number, color?: Color, time?: number, rotation?: Vector3): void;
7830
+ /** Draw a debug wireframe sphere as three rings
7831
+ * @param {Vector3} pos - Center
7832
+ * @param {number} [size] - Diameter
7833
+ * @param {Color} [color]
7834
+ * @param {number} [time] - How long to show it, 0 is one frame
7835
+ * @memberof Render3D */
7836
+ export function debugSphere3D(pos: Vector3, size?: number, color?: Color, time?: number): void;
7837
+ /** Draw a debug line
7838
+ * @param {Vector3} posA
7839
+ * @param {Vector3} posB
7840
+ * @param {Color} [color]
7841
+ * @param {number} [width]
7842
+ * @param {number} [time] - How long to show it, 0 is one frame
7843
+ * @memberof Render3D */
7844
+ export function debugLine3D(posA: Vector3, posB: Vector3, color?: Color, width?: number, time?: number): void;
7845
+ /** Draw a debug point as a small cross of three lines
7846
+ * @param {Vector3} pos
7847
+ * @param {Color} [color]
7848
+ * @param {number} [time] - How long to show it, 0 is one frame
7849
+ * @param {number} [size] - Length of the cross
7850
+ * @memberof Render3D */
7851
+ export function debugPoint3D(pos: Vector3, color?: Color, time?: number, size?: number): void;
5801
7852
  /**
5802
7853
  * LittleJS Three.js Plugin
5803
7854
  * - Renders a three.js scene on a canvas behind the LittleJS canvases
@@ -5906,10 +7957,10 @@ declare module "littlejsengine" {
5906
7957
  constructor(size?: number);
5907
7958
  /** @property {number} - Width and height of the sheet in pixels */
5908
7959
  size: number;
5909
- /** @property {OffscreenCanvas} - Canvas holding the packed images */
5910
- canvas: OffscreenCanvas;
5911
7960
  /** @property {OffscreenCanvasRenderingContext2D} - 2d context for the canvas */
5912
7961
  context: OffscreenCanvasRenderingContext2D;
7962
+ /** @property {OffscreenCanvas} - Canvas holding the packed images */
7963
+ canvas: OffscreenCanvas;
5913
7964
  /** @property {TextureInfo} - The texture info for this sheet */
5914
7965
  textureInfo: TextureInfo;
5915
7966
  /** @property {Vector2} - Where the next image will be packed */