@woosh/meep-engine 2.43.52 → 2.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/cache/Cache.d.ts +3 -0
- package/core/geom/3d/frustum/read_cluster_frustum_corners.js +46 -0
- package/core/geom/3d/frustum/slice_frustum_linear_to_points.js +92 -0
- package/core/model/object/compareObjectsByNumericId.js +9 -0
- package/engine/ecs/transform/Transform.d.ts +4 -2
- package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +4 -2
- package/engine/graphics/render/forward_plus/LightManager.js +277 -277
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +3 -62
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_APPLY_DECALS.js +70 -0
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_LOAD_METADATA.js +11 -0
- package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +10 -3
- package/engine/graphics/render/forward_plus/materials/fp_build_vertex_lighting_shared.js +5 -2
- package/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +2 -3
- package/engine/intelligence/behavior/SelectorBehavior.js +36 -6
- package/engine/sound/sopra/AbstractAudioClip.js +29 -0
- package/engine/sound/sopra/ContainerAudioClip.js +13 -0
- package/engine/sound/sopra/README.md +1 -0
- package/engine/sound/sopra/RandomContainerAudioClip.js +15 -0
- package/engine/sound/sopra/SequenceContainerAudioClip.js +8 -0
- package/engine/sound/sopra/SilenceAudioClip.js +15 -0
- package/package.json +1 -1
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
export const FP_SHADER_CHUNK_ACCUMULATION = `
|
|
2
2
|
#ifndef FP_SHADER_CHUNK_ACCUMULATION
|
|
3
3
|
#define FP_SHADER_CHUNK_ACCUMULATION
|
|
4
|
-
|
|
5
|
-
ivec3 v3_cluster_resolution = textureSize(fp_t_light_tiles, 0);
|
|
6
|
-
ivec3 v3_cluster_position = ivec3( clip_v.x * float(v3_cluster_resolution.x), clip_v.y*float(v3_cluster_resolution.y), (clip_v.z)*float(v3_cluster_resolution.z) );
|
|
7
|
-
|
|
8
|
-
uvec3 cluster_metadata = texelFetch(fp_t_light_tiles, v3_cluster_position , 0).rgb;
|
|
9
|
-
|
|
4
|
+
|
|
10
5
|
// read light data
|
|
11
|
-
for(uint i=0u; i <
|
|
12
|
-
uint lookup_index =
|
|
6
|
+
for(uint i=0u; i < fp_cluster_metadata.y; i++){
|
|
7
|
+
uint lookup_index = fp_cluster_metadata.x + i;
|
|
13
8
|
|
|
14
9
|
uint light_descriptor = texelFetch(fp_t_light_lookup, address_to_data_texture_coordinates(lookup_index), 0 ).r;
|
|
15
10
|
|
|
@@ -39,60 +34,6 @@ export const FP_SHADER_CHUNK_ACCUMULATION = `
|
|
|
39
34
|
fp_getPointDirectLightIrradiance( pointlight, directLight, vViewPosition );
|
|
40
35
|
RE_Direct( directLight, geometry, material, reflectedLight );
|
|
41
36
|
|
|
42
|
-
}else if(type == 3u){
|
|
43
|
-
// decal
|
|
44
|
-
vec4 light_data_0 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address), 0);
|
|
45
|
-
vec4 light_data_1 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address+1u), 0);
|
|
46
|
-
vec4 light_data_2 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address+2u), 0);
|
|
47
|
-
vec4 light_data_3 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address+3u), 0);
|
|
48
|
-
|
|
49
|
-
mat4 decal_transform_matrix = mat4(
|
|
50
|
-
light_data_0,
|
|
51
|
-
light_data_1,
|
|
52
|
-
light_data_2,
|
|
53
|
-
light_data_3
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
vec4 local_position = decal_transform_matrix*vec4(v_world_position, 1.0);
|
|
57
|
-
|
|
58
|
-
if(max3(abs(local_position.xyz)) < 0.5){
|
|
59
|
-
|
|
60
|
-
// we're inside decal volume
|
|
61
|
-
vec4 light_data_4 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address+4u), 0);
|
|
62
|
-
|
|
63
|
-
// compute normal of the decal, we get this by extracting rotation matrix and transforming (0,1,0) vector using that
|
|
64
|
-
vec3 decal_normal = normalize(vec3(
|
|
65
|
-
decal_transform_matrix[0][2], decal_transform_matrix[1][2], decal_transform_matrix[2][2]
|
|
66
|
-
));
|
|
67
|
-
|
|
68
|
-
// Get geometry normal in world-space
|
|
69
|
-
vec3 g_normal = normalize( ( transpose(viewMatrix) * vec4( geometry.normal, 0.0 ) ).xyz );
|
|
70
|
-
|
|
71
|
-
float decal_surface_dot = dot(decal_normal, g_normal);
|
|
72
|
-
|
|
73
|
-
// we fade out decals when the projection angle to the surface gets too steep
|
|
74
|
-
// 0.7 is cos(45deg) and 0.5 is cos(60deg), dot returns cos of angle between two normals
|
|
75
|
-
float decal_surface_angle_fade = smoothstep(-0.5,-0.7,decal_surface_dot);
|
|
76
|
-
|
|
77
|
-
if(decal_surface_angle_fade <= 0.0){
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
vec2 decal_local_uv = (local_position.xy + 0.5);
|
|
82
|
-
vec2 decal_uv = decal_local_uv*light_data_4.zw + light_data_4.xy;
|
|
83
|
-
|
|
84
|
-
vec4 decal_color = texture2D(fp_t_decal_atlas,decal_uv, -0.2);
|
|
85
|
-
|
|
86
|
-
// compute decal alpha
|
|
87
|
-
float decal_alpha = decal_color.a * decal_surface_angle_fade;
|
|
88
|
-
|
|
89
|
-
if(decal_alpha < 0.003){
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
material.diffuseColor = material.diffuseColor*(1.0-decal_alpha) + decal_color.xyz*decal_alpha;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
37
|
}
|
|
97
38
|
}
|
|
98
39
|
#endif
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export const FP_SHADER_CHUNK_APPLY_DECALS = `
|
|
2
|
+
#ifndef FP_SHADER_CHUNK_APPLY_DECALS
|
|
3
|
+
#define FP_SHADER_CHUNK_APPLY_DECALS
|
|
4
|
+
|
|
5
|
+
// process decals
|
|
6
|
+
for(uint i=0u; i < fp_cluster_metadata.w; i++){
|
|
7
|
+
uint lookup_index = fp_cluster_metadata.z + i;
|
|
8
|
+
|
|
9
|
+
uint light_descriptor = texelFetch(fp_t_light_lookup, address_to_data_texture_coordinates(lookup_index), 0 ).r;
|
|
10
|
+
|
|
11
|
+
uint type = (light_descriptor) & 0x3u;
|
|
12
|
+
uint light_address = light_descriptor >> 2;
|
|
13
|
+
|
|
14
|
+
// decal
|
|
15
|
+
vec4 light_data_0 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address), 0);
|
|
16
|
+
vec4 light_data_1 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address+1u), 0);
|
|
17
|
+
vec4 light_data_2 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address+2u), 0);
|
|
18
|
+
vec4 light_data_3 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address+3u), 0);
|
|
19
|
+
|
|
20
|
+
mat4 decal_transform_matrix = mat4(
|
|
21
|
+
light_data_0,
|
|
22
|
+
light_data_1,
|
|
23
|
+
light_data_2,
|
|
24
|
+
light_data_3
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
vec4 local_position = decal_transform_matrix*vec4(v_world_position, 1.0);
|
|
28
|
+
|
|
29
|
+
if(max3(abs(local_position.xyz)) < 0.5){
|
|
30
|
+
|
|
31
|
+
// we're inside decal volume
|
|
32
|
+
vec4 light_data_4 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address+4u), 0);
|
|
33
|
+
|
|
34
|
+
// compute normal of the decal, we get this by extracting rotation matrix and transforming (0,1,0) vector using that
|
|
35
|
+
vec3 decal_normal = normalize(vec3(
|
|
36
|
+
decal_transform_matrix[0][2], decal_transform_matrix[1][2], decal_transform_matrix[2][2]
|
|
37
|
+
));
|
|
38
|
+
|
|
39
|
+
// Get geometry normal in world-space
|
|
40
|
+
vec3 g_normal = normalize( ( transpose(viewMatrix) * vec4( normal, 0.0 ) ).xyz );
|
|
41
|
+
|
|
42
|
+
float decal_surface_dot = dot(decal_normal, g_normal);
|
|
43
|
+
|
|
44
|
+
// we fade out decals when the projection angle to the surface gets too steep
|
|
45
|
+
// 0.7 is cos(45deg) and 0.5 is cos(60deg), dot returns cos of angle between two normals
|
|
46
|
+
float decal_surface_angle_fade = smoothstep(-0.5,-0.7,decal_surface_dot);
|
|
47
|
+
|
|
48
|
+
if(decal_surface_angle_fade <= 0.0){
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
vec2 decal_local_uv = (local_position.xy + 0.5);
|
|
53
|
+
vec2 decal_uv = decal_local_uv*light_data_4.zw + light_data_4.xy;
|
|
54
|
+
|
|
55
|
+
vec4 decal_color = texture2D(fp_t_decal_atlas,decal_uv, -0.2);
|
|
56
|
+
|
|
57
|
+
// compute decal alpha
|
|
58
|
+
float decal_alpha = decal_color.a * decal_surface_angle_fade;
|
|
59
|
+
|
|
60
|
+
if(decal_alpha < 0.003){
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
material.diffuseColor = material.diffuseColor*(1.0-decal_alpha) + decal_color.xyz*decal_alpha;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#endif
|
|
70
|
+
`;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const FP_SHADER_CHUNK_LOAD_METADATA = `
|
|
2
|
+
#ifndef FP_SHADER_CHUNK_LOAD_METADATA
|
|
3
|
+
#define FP_SHADER_CHUNK_LOAD_METADATA
|
|
4
|
+
|
|
5
|
+
ivec3 v3_cluster_resolution = textureSize(fp_t_light_tiles, 0);
|
|
6
|
+
ivec3 v3_cluster_position = ivec3( clip_v.x * float(v3_cluster_resolution.x), clip_v.y*float(v3_cluster_resolution.y), (clip_v.z)*float(v3_cluster_resolution.z) );
|
|
7
|
+
|
|
8
|
+
uvec4 fp_cluster_metadata = texelFetch( fp_t_light_tiles, v3_cluster_position, 0 ).rgba;
|
|
9
|
+
|
|
10
|
+
#endif
|
|
11
|
+
`;
|
|
@@ -4,13 +4,16 @@ import { FP_SHADER_CHUNK_ACCUMULATION } from "./FP_SHADER_CHUNK_ACCUMULATION.js"
|
|
|
4
4
|
import { FP_SHADER_CHUNK_DECODE_PARS } from "./FP_SHADER_CHUNK_DECODE_PARS.js";
|
|
5
5
|
import { FP_INJECTION_POINT_ACCUMULATION } from "./FP_INJECTION_POINT_ACCUMULATION.js";
|
|
6
6
|
import { FP_SHADER_CHUNK_PREAMBLE } from "./FP_SHADER_CHUNK_PREAMBLE.js";
|
|
7
|
+
import { insert_before } from "../../../../../core/primitives/strings/insert_before.js";
|
|
8
|
+
import { FP_SHADER_CHUNK_APPLY_DECALS } from "./FP_SHADER_CHUNK_APPLY_DECALS.js";
|
|
9
|
+
import { FP_SHADER_CHUNK_LOAD_METADATA } from "./FP_SHADER_CHUNK_LOAD_METADATA.js";
|
|
7
10
|
|
|
8
11
|
const three_chunk_accummulation_mark = '#include <lights_fragment_begin>';
|
|
9
12
|
|
|
10
13
|
const accumulation_pars = `
|
|
11
14
|
vec3 clip_v = vec3( vec2(gl_FragCoord.x, gl_FragCoord.y) / fp_resolution, convert_depth_to_linear(gl_FragCoord.z));
|
|
12
15
|
clip_v.x = 1.0 - clip_v.x;
|
|
13
|
-
${
|
|
16
|
+
${FP_SHADER_CHUNK_LOAD_METADATA}
|
|
14
17
|
`;
|
|
15
18
|
|
|
16
19
|
const preamble = `
|
|
@@ -38,15 +41,19 @@ export function fp_build_fragment_shader(base) {
|
|
|
38
41
|
`;
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
result = result + base
|
|
44
|
+
result = result + base;
|
|
45
|
+
|
|
46
|
+
result = insert_after(result, 'void main() {', accumulation_pars);
|
|
42
47
|
|
|
43
48
|
result = insert_after(result, '#include <lights_pars_begin>', FP_SHADER_CHUNK_DECODE_PARS);
|
|
44
49
|
|
|
50
|
+
result = insert_before(result, '#include <lights_fragment_begin>', FP_SHADER_CHUNK_APPLY_DECALS);
|
|
51
|
+
|
|
45
52
|
result = insert_after_or_replace(
|
|
46
53
|
result,
|
|
47
54
|
three_chunk_accummulation_mark,
|
|
48
55
|
FP_INJECTION_POINT_ACCUMULATION,
|
|
49
|
-
|
|
56
|
+
FP_SHADER_CHUNK_ACCUMULATION
|
|
50
57
|
);
|
|
51
58
|
|
|
52
59
|
return result;
|
|
@@ -4,11 +4,12 @@ import { FP_INJECTION_POINT_ACCUMULATION } from "./FP_INJECTION_POINT_ACCUMULATI
|
|
|
4
4
|
import { FP_SHADER_CHUNK_ACCUMULATION } from "./FP_SHADER_CHUNK_ACCUMULATION.js";
|
|
5
5
|
import { FP_SHADER_CHUNK_PREAMBLE } from "./FP_SHADER_CHUNK_PREAMBLE.js";
|
|
6
6
|
import { FP_SHADER_CHUNK_DECODE_PARS } from "./FP_SHADER_CHUNK_DECODE_PARS.js";
|
|
7
|
+
import { FP_SHADER_CHUNK_LOAD_METADATA } from "./FP_SHADER_CHUNK_LOAD_METADATA.js";
|
|
7
8
|
|
|
8
9
|
const accumulation_pars = `
|
|
9
10
|
vec3 fp_normalized_screen_position = ((gl_Position.xyz / gl_Position.w)+vec3(1.0))*0.5;
|
|
10
11
|
vec3 clip_v = vec3( vec2(fp_normalized_screen_position.x, fp_normalized_screen_position.y), convert_depth_to_linear(fp_normalized_screen_position.z));
|
|
11
|
-
${
|
|
12
|
+
${FP_SHADER_CHUNK_LOAD_METADATA}
|
|
12
13
|
`;
|
|
13
14
|
|
|
14
15
|
const three_chunk_accummulation_mark = '#include <lights_fragment_end>';
|
|
@@ -22,13 +23,15 @@ export function fp_build_vertex_lighting_shared(base) {
|
|
|
22
23
|
|
|
23
24
|
let result = FP_SHADER_CHUNK_PREAMBLE + base;
|
|
24
25
|
|
|
26
|
+
result = insert_after(result, 'void main() {', accumulation_pars);
|
|
27
|
+
|
|
25
28
|
result = insert_after(result, '#include <lights_pars_begin>', FP_SHADER_CHUNK_DECODE_PARS);
|
|
26
29
|
|
|
27
30
|
result = insert_after_or_replace(
|
|
28
31
|
result,
|
|
29
32
|
three_chunk_accummulation_mark,
|
|
30
33
|
FP_INJECTION_POINT_ACCUMULATION,
|
|
31
|
-
|
|
34
|
+
FP_SHADER_CHUNK_ACCUMULATION
|
|
32
35
|
);
|
|
33
36
|
|
|
34
37
|
return result;
|
|
@@ -1558,12 +1558,11 @@ function draw_camera_view_planes() {
|
|
|
1558
1558
|
});
|
|
1559
1559
|
}
|
|
1560
1560
|
|
|
1561
|
-
|
|
1561
|
+
prepare_scene_2();
|
|
1562
1562
|
// prepare_scene_decal_0();
|
|
1563
1563
|
// prepare_scene_decal_1();
|
|
1564
|
-
prepare_scene_decal_2();
|
|
1564
|
+
// prepare_scene_decal_2();
|
|
1565
1565
|
// prepare_scene_9();
|
|
1566
|
-
// prepare_scene_2();
|
|
1567
1566
|
// prepare_scene_0();
|
|
1568
1567
|
animate();
|
|
1569
1568
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { CompositeBehavior } from "./composite/CompositeBehavior.js";
|
|
2
2
|
import { BehaviorStatus } from "./BehaviorStatus.js";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Will try every child behaviour in order until one succeeds or if all fail - the selector behavior will fail too
|
|
6
|
+
*/
|
|
4
7
|
export class SelectorBehavior extends CompositeBehavior {
|
|
5
8
|
constructor() {
|
|
6
9
|
super();
|
|
@@ -35,23 +38,50 @@ export class SelectorBehavior extends CompositeBehavior {
|
|
|
35
38
|
return s;
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
this.__currentBehaviour.finalize();
|
|
42
|
+
|
|
38
43
|
//Continue search for a fallback until the last child
|
|
39
44
|
const children = this.__children;
|
|
40
|
-
|
|
45
|
+
|
|
46
|
+
this.__currentBehaviourIndex++;
|
|
47
|
+
|
|
48
|
+
if (this.__currentBehaviourIndex >= children.length) {
|
|
49
|
+
this.__currentBehaviour = null;
|
|
50
|
+
|
|
41
51
|
return BehaviorStatus.Failed;
|
|
42
52
|
}
|
|
43
53
|
|
|
44
|
-
this.__currentBehaviourIndex++;
|
|
45
54
|
this.__currentBehaviour = children[this.__currentBehaviourIndex];
|
|
55
|
+
|
|
56
|
+
this.__currentBehaviour.initialize(this.context);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
finalize() {
|
|
61
|
+
if (this.__currentBehaviour !== null) {
|
|
62
|
+
this.__currentBehaviour.finalize();
|
|
63
|
+
this.__currentBehaviour = null;
|
|
46
64
|
}
|
|
47
65
|
}
|
|
48
66
|
|
|
49
67
|
initialize(context) {
|
|
50
68
|
super.initialize(context);
|
|
51
|
-
|
|
52
|
-
this.__currentBehaviourIndex = 0;
|
|
53
|
-
this.__currentBehaviour = this.__children[0];
|
|
54
69
|
|
|
55
|
-
this.
|
|
70
|
+
const children = this.__children;
|
|
71
|
+
|
|
72
|
+
if (children.length > 0) {
|
|
73
|
+
|
|
74
|
+
this.__currentBehaviourIndex = 0;
|
|
75
|
+
this.__currentBehaviour = children[0];
|
|
76
|
+
|
|
77
|
+
this.__currentBehaviour.initialize();
|
|
78
|
+
|
|
79
|
+
} else {
|
|
80
|
+
// no children
|
|
81
|
+
|
|
82
|
+
this.__currentBehaviourIndex = -1;
|
|
83
|
+
this.__currentBehaviour = null;
|
|
84
|
+
|
|
85
|
+
}
|
|
56
86
|
}
|
|
57
87
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for all audio clips
|
|
3
|
+
*/
|
|
4
|
+
export class AbstractAudioClip {
|
|
5
|
+
/**
|
|
6
|
+
* Parent clip, if set - will propagate various parameters to the child at play-time
|
|
7
|
+
* @type {null}
|
|
8
|
+
*/
|
|
9
|
+
parent = null;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Relative offset from source
|
|
13
|
+
* @type {number}
|
|
14
|
+
*/
|
|
15
|
+
pitch = 0;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Gain offset in decibel
|
|
19
|
+
* @type {number}
|
|
20
|
+
*/
|
|
21
|
+
gain = 0;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Output channel, if not set - will use a settings from parent
|
|
25
|
+
* @type {null}
|
|
26
|
+
*/
|
|
27
|
+
channel = null;
|
|
28
|
+
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Loosely based on concepts from FMOD and Wwise
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ContainerAudioClip } from "./ContainerAudioClip.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* When being played back, will play a random child element
|
|
5
|
+
*/
|
|
6
|
+
export class RandomContainerAudioClip extends ContainerAudioClip {
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Try not to repeat last X played sounds
|
|
11
|
+
* @type {number}
|
|
12
|
+
*/
|
|
13
|
+
avoid_repeating_last = 1;
|
|
14
|
+
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AbstractAudioClip } from "./AbstractAudioClip.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents dead air
|
|
5
|
+
* @example useful for introducing pauses in sequences
|
|
6
|
+
*/
|
|
7
|
+
export class SilenceAudioClip extends AbstractAudioClip {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Duration of the silence
|
|
11
|
+
* @type {number}
|
|
12
|
+
*/
|
|
13
|
+
duration = 0;
|
|
14
|
+
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"productName": "Meep",
|
|
6
6
|
"description": "production-ready JavaScript game engine based on Entity Component System Architecture",
|
|
7
7
|
"author": "Alexander Goldring",
|
|
8
|
-
"version": "2.
|
|
8
|
+
"version": "2.44.0",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"gl-matrix": "3.4.3",
|
|
11
11
|
"fast-levenshtein": "2.0.6",
|