@auraindustry/aurajs 0.0.5 → 0.0.6
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/README.md +4 -2
- package/benchmarks/perf-thresholds.json +27 -0
- package/package.json +2 -1
- package/src/build-contract.mjs +1644 -56
- package/src/cli.mjs +1048 -321
- package/src/conformance.mjs +356 -11
- package/src/cutscene.mjs +205 -0
- package/src/game-state-runtime.mjs +260 -0
- package/src/headless-test.mjs +92 -9
- package/src/perf-benchmark.mjs +103 -0
- package/src/scaffold.mjs +413 -13
- package/src/state-artifacts.mjs +321 -0
- package/src/state-dev-reload.mjs +120 -0
- package/templates/create/2d-survivor/aura.config.json +28 -0
- package/templates/create/2d-survivor/src/main.js +344 -0
- package/templates/create/3d-collectathon/aura.config.json +28 -0
- package/templates/create/3d-collectathon/src/main.js +367 -0
- package/templates/skills/aurajs/api-contract-3d.md +1 -1
- package/templates/skills/aurajs/api-contract.md +1 -1
- package/src/.gitkeep +0 -0
package/src/build-contract.mjs
CHANGED
|
@@ -14,6 +14,8 @@ import { extname, relative, resolve, sep } from 'node:path';
|
|
|
14
14
|
export const BUILD_MANIFEST_SCHEMA = 'aurajs.build-manifest.v1';
|
|
15
15
|
export const WEB_BUILD_MANIFEST_SCHEMA = 'aurajs.web-build-manifest.v1';
|
|
16
16
|
export const WEB_RUNTIME_CONFIG_SCHEMA = 'aurajs.web-runtime-config.v1';
|
|
17
|
+
export const WEB_CAPABILITY_DECLARATION_SCHEMA = 'aurajs.web-capability-declaration.v1';
|
|
18
|
+
const PROJECT_CAPABILITY_DECLARATION_FILE = 'aura.capabilities.json';
|
|
17
19
|
|
|
18
20
|
export function writeBuildManifest(options = {}) {
|
|
19
21
|
const outRoot = resolve(options.outRoot || process.cwd());
|
|
@@ -76,9 +78,14 @@ export function writeWebBuildArtifacts(options = {}) {
|
|
|
76
78
|
outRoot,
|
|
77
79
|
});
|
|
78
80
|
|
|
81
|
+
const capabilityDeclaration = readProjectCapabilityDeclaration({
|
|
82
|
+
projectRoot,
|
|
83
|
+
modules: options.modules || {},
|
|
84
|
+
});
|
|
79
85
|
const runtimeConfig = buildRuntimeConfig({
|
|
80
86
|
windowConfig: options.windowConfig || {},
|
|
81
87
|
modules: options.modules || {},
|
|
88
|
+
capabilityDeclaration,
|
|
82
89
|
});
|
|
83
90
|
const runtimeConfigPath = resolve(outRoot, 'runtime-config.json');
|
|
84
91
|
writeCanonicalJson(runtimeConfigPath, runtimeConfig);
|
|
@@ -156,6 +163,13 @@ function buildRuntimeConfig(options = {}) {
|
|
|
156
163
|
const modules = options.modules && typeof options.modules === 'object'
|
|
157
164
|
? options.modules
|
|
158
165
|
: {};
|
|
166
|
+
const capabilityDeclaration = normalizeWebCapabilityDeclaration(
|
|
167
|
+
options.capabilityDeclaration,
|
|
168
|
+
normalizeOptionalModules(modules),
|
|
169
|
+
options.capabilityDeclaration && typeof options.capabilityDeclaration === 'object'
|
|
170
|
+
? options.capabilityDeclaration.source || null
|
|
171
|
+
: null,
|
|
172
|
+
);
|
|
159
173
|
|
|
160
174
|
return {
|
|
161
175
|
schema: WEB_RUNTIME_CONFIG_SCHEMA,
|
|
@@ -176,9 +190,79 @@ function buildRuntimeConfig(options = {}) {
|
|
|
176
190
|
network: modules.network === true,
|
|
177
191
|
multiplayer: modules.multiplayer === true,
|
|
178
192
|
},
|
|
193
|
+
capabilities: capabilityDeclaration,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function normalizeRequiredApis(entries) {
|
|
198
|
+
if (!Array.isArray(entries)) {
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
return [...new Set(entries
|
|
202
|
+
.filter((entry) => typeof entry === 'string')
|
|
203
|
+
.map((entry) => entry.trim())
|
|
204
|
+
.filter(Boolean))]
|
|
205
|
+
.sort((a, b) => a.localeCompare(b));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function normalizeOptionalModules(modules) {
|
|
209
|
+
const source = modules && typeof modules === 'object' ? modules : {};
|
|
210
|
+
return {
|
|
211
|
+
physics: source.physics === true,
|
|
212
|
+
network: source.network === true || source.net === true,
|
|
213
|
+
multiplayer: source.multiplayer === true,
|
|
214
|
+
steam: source.steam === true,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function normalizeWebCapabilityDeclaration(value, baseModules = {}, source = null) {
|
|
219
|
+
const declaration = value && typeof value === 'object' && !Array.isArray(value)
|
|
220
|
+
? value
|
|
221
|
+
: {};
|
|
222
|
+
if (
|
|
223
|
+
declaration.schema != null
|
|
224
|
+
&& declaration.schema !== 'aurajs.create-capabilities.v1'
|
|
225
|
+
&& declaration.schema !== 'aurajs.capability-declaration.v1'
|
|
226
|
+
&& declaration.schema !== WEB_CAPABILITY_DECLARATION_SCHEMA
|
|
227
|
+
) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`${source || 'Capability declaration'} must use `
|
|
230
|
+
+ '`aurajs.create-capabilities.v1`, `aurajs.capability-declaration.v1`, '
|
|
231
|
+
+ `or \`${WEB_CAPABILITY_DECLARATION_SCHEMA}\`.`,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const declaredModules = normalizeOptionalModules(declaration.optionalModules);
|
|
236
|
+
return {
|
|
237
|
+
schema: WEB_CAPABILITY_DECLARATION_SCHEMA,
|
|
238
|
+
source,
|
|
239
|
+
requiredApis: normalizeRequiredApis(declaration.requiredApis),
|
|
240
|
+
optionalModules: {
|
|
241
|
+
physics: baseModules.physics || declaredModules.physics,
|
|
242
|
+
network: baseModules.network || declaredModules.network,
|
|
243
|
+
multiplayer: baseModules.multiplayer || declaredModules.multiplayer,
|
|
244
|
+
steam: baseModules.steam || declaredModules.steam,
|
|
245
|
+
},
|
|
179
246
|
};
|
|
180
247
|
}
|
|
181
248
|
|
|
249
|
+
function readProjectCapabilityDeclaration({ projectRoot, modules }) {
|
|
250
|
+
const declarationPath = resolve(projectRoot, PROJECT_CAPABILITY_DECLARATION_FILE);
|
|
251
|
+
const baseModules = normalizeOptionalModules(modules);
|
|
252
|
+
if (!existsSync(declarationPath)) {
|
|
253
|
+
return normalizeWebCapabilityDeclaration({}, baseModules, null);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
let parsed;
|
|
257
|
+
try {
|
|
258
|
+
parsed = JSON.parse(readFileSync(declarationPath, 'utf8'));
|
|
259
|
+
} catch (error) {
|
|
260
|
+
throw new Error(`Failed to parse ${PROJECT_CAPABILITY_DECLARATION_FILE}: ${error.message}`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return normalizeWebCapabilityDeclaration(parsed, baseModules, PROJECT_CAPABILITY_DECLARATION_FILE);
|
|
264
|
+
}
|
|
265
|
+
|
|
182
266
|
function emitWebAssets({ projectRoot, outRoot }) {
|
|
183
267
|
const sourceRoot = resolve(projectRoot, 'assets');
|
|
184
268
|
const assetsOutRoot = resolve(outRoot, 'assets');
|
|
@@ -203,6 +287,7 @@ function emitWebAssets({ projectRoot, outRoot }) {
|
|
|
203
287
|
copyFileSync(sourcePath, outputPath);
|
|
204
288
|
entries.push({
|
|
205
289
|
path: `assets/${outputName}`,
|
|
290
|
+
sourcePath: sourceRelative,
|
|
206
291
|
bytes: sourceBytes.length,
|
|
207
292
|
sha256: contentHash,
|
|
208
293
|
mediaType: mediaTypeForExtension(extension),
|
|
@@ -349,6 +434,7 @@ const WEB_LOADER_SOURCE = `
|
|
|
349
434
|
};
|
|
350
435
|
let cachedManifest = null;
|
|
351
436
|
let cachedRuntimeConfig = null;
|
|
437
|
+
let cachedRootUrl = '.';
|
|
352
438
|
let mountedRuntime = null;
|
|
353
439
|
let auraRuntime = null;
|
|
354
440
|
|
|
@@ -392,6 +478,33 @@ const WEB_LOADER_SOURCE = `
|
|
|
392
478
|
return error;
|
|
393
479
|
}
|
|
394
480
|
|
|
481
|
+
function createUnsupportedRuntimeError(namespaceName, methodName, reasonCode, details) {
|
|
482
|
+
const normalizedDetails = details && typeof details === 'object' ? details : {};
|
|
483
|
+
return createError(
|
|
484
|
+
reasonCode,
|
|
485
|
+
'aura.' + namespaceName + '.' + methodName + '() is not supported in browser runtime. [reason:' + reasonCode + ']',
|
|
486
|
+
'runtime',
|
|
487
|
+
false,
|
|
488
|
+
Object.assign(
|
|
489
|
+
{
|
|
490
|
+
runtime: 'web',
|
|
491
|
+
namespace: namespaceName,
|
|
492
|
+
method: methodName
|
|
493
|
+
},
|
|
494
|
+
normalizedDetails
|
|
495
|
+
)
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function createUnsupportedStateResult(methodName, reasonCode) {
|
|
500
|
+
return {
|
|
501
|
+
ok: false,
|
|
502
|
+
reasonCode: reasonCode,
|
|
503
|
+
detail: 'aura.state.' + methodName + '() is not supported in browser runtime. [reason:' + reasonCode + ']',
|
|
504
|
+
runtime: 'web'
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
|
|
395
508
|
function normalizeError(error, fallbackReasonCode, fallbackMessage, fallbackLayer, fallbackRetryable) {
|
|
396
509
|
if (error && typeof error === 'object' && typeof error.reasonCode === 'string') {
|
|
397
510
|
return error;
|
|
@@ -525,6 +638,45 @@ const WEB_LOADER_SOURCE = `
|
|
|
525
638
|
return numeric;
|
|
526
639
|
}
|
|
527
640
|
|
|
641
|
+
function toFinite(value, fallback) {
|
|
642
|
+
const numeric = Number(value);
|
|
643
|
+
return Number.isFinite(numeric) ? numeric : fallback;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function toPositive(value, fallback) {
|
|
647
|
+
const numeric = Number(value);
|
|
648
|
+
return Number.isFinite(numeric) && numeric > 0 ? numeric : fallback;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function clamp01(value) {
|
|
652
|
+
const numeric = Number(value);
|
|
653
|
+
if (!Number.isFinite(numeric)) return 1;
|
|
654
|
+
if (numeric <= 0) return 0;
|
|
655
|
+
if (numeric >= 1) return 1;
|
|
656
|
+
return numeric;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function isObject(value) {
|
|
660
|
+
return value != null && typeof value === 'object';
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function normalizeMouseButton(value) {
|
|
664
|
+
const numeric = Number(value);
|
|
665
|
+
if (!Number.isFinite(numeric) || numeric < 0) return 0;
|
|
666
|
+
return Math.floor(numeric);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function sanitizeAssetSourcePath(value) {
|
|
670
|
+
return String(value || '')
|
|
671
|
+
.replace(/\\\\/g, '/')
|
|
672
|
+
.replace(/^\\.\\//, '')
|
|
673
|
+
.replace(/^\\/+/, '');
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function isImageMediaType(value) {
|
|
677
|
+
return typeof value === 'string' && value.startsWith('image/');
|
|
678
|
+
}
|
|
679
|
+
|
|
528
680
|
function normalizeTextAlign(value) {
|
|
529
681
|
if (value === 'center' || value === 'right' || value === 'left') {
|
|
530
682
|
return value;
|
|
@@ -614,6 +766,122 @@ const WEB_LOADER_SOURCE = `
|
|
|
614
766
|
}
|
|
615
767
|
}
|
|
616
768
|
|
|
769
|
+
function normalizeCapabilityDeclaration(value) {
|
|
770
|
+
const declaration = value && typeof value === 'object' ? value : {};
|
|
771
|
+
const requiredApis = Array.isArray(declaration.requiredApis)
|
|
772
|
+
? Array.from(new Set(declaration.requiredApis
|
|
773
|
+
.filter(function (entry) { return typeof entry === 'string'; })
|
|
774
|
+
.map(function (entry) { return entry.trim(); })
|
|
775
|
+
.filter(Boolean)))
|
|
776
|
+
.sort(function (a, b) { return a.localeCompare(b); })
|
|
777
|
+
: [];
|
|
778
|
+
const declaredModules = declaration.optionalModules && typeof declaration.optionalModules === 'object'
|
|
779
|
+
? declaration.optionalModules
|
|
780
|
+
: {};
|
|
781
|
+
return {
|
|
782
|
+
schema: typeof declaration.schema === 'string'
|
|
783
|
+
? declaration.schema
|
|
784
|
+
: 'aurajs.web-capability-declaration.v1',
|
|
785
|
+
source: typeof declaration.source === 'string' ? declaration.source : null,
|
|
786
|
+
requiredApis: requiredApis,
|
|
787
|
+
optionalModules: {
|
|
788
|
+
physics: declaredModules.physics === true,
|
|
789
|
+
network: declaredModules.network === true,
|
|
790
|
+
multiplayer: declaredModules.multiplayer === true,
|
|
791
|
+
steam: declaredModules.steam === true
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
function resolveDeclaredApi(root, apiPath) {
|
|
797
|
+
if (typeof apiPath !== 'string' || apiPath.length === 0) {
|
|
798
|
+
return { found: false, value: undefined };
|
|
799
|
+
}
|
|
800
|
+
const segments = apiPath.split('.').filter(Boolean);
|
|
801
|
+
let current = root;
|
|
802
|
+
for (const segment of segments) {
|
|
803
|
+
if (
|
|
804
|
+
current == null
|
|
805
|
+
|| (typeof current !== 'object' && typeof current !== 'function')
|
|
806
|
+
|| !(segment in current)
|
|
807
|
+
) {
|
|
808
|
+
return { found: false, value: undefined };
|
|
809
|
+
}
|
|
810
|
+
current = current[segment];
|
|
811
|
+
}
|
|
812
|
+
return { found: current != null, value: current };
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
function collectCapabilityFailures(runtimeConfig, auraRef) {
|
|
816
|
+
const declaration = normalizeCapabilityDeclaration(runtimeConfig && runtimeConfig.capabilities);
|
|
817
|
+
const failures = [];
|
|
818
|
+
const root = { aura: auraRef && typeof auraRef === 'object' ? auraRef : {} };
|
|
819
|
+
|
|
820
|
+
for (const moduleName of ['physics', 'network', 'multiplayer', 'steam']) {
|
|
821
|
+
if (declaration.optionalModules[moduleName] === true) {
|
|
822
|
+
failures.push({
|
|
823
|
+
kind: 'optionalModule',
|
|
824
|
+
module: moduleName,
|
|
825
|
+
reasonCode: 'web_optional_module_unsupported'
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
for (const apiPath of declaration.requiredApis) {
|
|
831
|
+
const resolved = resolveDeclaredApi(root, apiPath);
|
|
832
|
+
if (!resolved.found) {
|
|
833
|
+
failures.push({
|
|
834
|
+
kind: 'requiredApi',
|
|
835
|
+
apiPath: apiPath,
|
|
836
|
+
reasonCode: 'web_required_api_missing'
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
return {
|
|
842
|
+
declaration: declaration,
|
|
843
|
+
failures: failures
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
function ensureCapabilityDeclarationSatisfied(runtimeConfig, auraRef) {
|
|
848
|
+
const report = collectCapabilityFailures(runtimeConfig, auraRef);
|
|
849
|
+
if (report.failures.length === 0) {
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
const missingRequiredApis = [];
|
|
854
|
+
const unsupportedOptionalModules = [];
|
|
855
|
+
for (const failure of report.failures) {
|
|
856
|
+
if (failure.kind === 'requiredApi') {
|
|
857
|
+
missingRequiredApis.push(failure.apiPath);
|
|
858
|
+
} else if (failure.kind === 'optionalModule') {
|
|
859
|
+
unsupportedOptionalModules.push(failure.module);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
let reasonCode = 'web_capability_gate_failed';
|
|
864
|
+
if (missingRequiredApis.length > 0 && unsupportedOptionalModules.length === 0) {
|
|
865
|
+
reasonCode = 'web_required_api_missing';
|
|
866
|
+
} else if (unsupportedOptionalModules.length > 0 && missingRequiredApis.length === 0) {
|
|
867
|
+
reasonCode = 'web_optional_module_unsupported';
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
throw createError(
|
|
871
|
+
reasonCode,
|
|
872
|
+
'Browser runtime does not satisfy the declared capability contract.',
|
|
873
|
+
'loader',
|
|
874
|
+
false,
|
|
875
|
+
{
|
|
876
|
+
schema: report.declaration.schema,
|
|
877
|
+
source: report.declaration.source,
|
|
878
|
+
missingRequiredApis: missingRequiredApis,
|
|
879
|
+
unsupportedOptionalModules: unsupportedOptionalModules,
|
|
880
|
+
failures: report.failures
|
|
881
|
+
}
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
|
|
617
885
|
function loadScript(path) {
|
|
618
886
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
619
887
|
const script = document.createElement('script');
|
|
@@ -633,6 +901,8 @@ const WEB_LOADER_SOURCE = `
|
|
|
633
901
|
let currentCanvasConfig = currentRuntimeConfig.canvas && typeof currentRuntimeConfig.canvas === 'object'
|
|
634
902
|
? currentRuntimeConfig.canvas
|
|
635
903
|
: {};
|
|
904
|
+
let currentManifest = { assets: [] };
|
|
905
|
+
let currentRootUrl = '.';
|
|
636
906
|
|
|
637
907
|
const auraRef = globalRef.aura && typeof globalRef.aura === 'object'
|
|
638
908
|
? globalRef.aura
|
|
@@ -644,7 +914,23 @@ const WEB_LOADER_SOURCE = `
|
|
|
644
914
|
pendingPressed: new Set(),
|
|
645
915
|
pendingReleased: new Set(),
|
|
646
916
|
framePressed: new Set(),
|
|
647
|
-
frameReleased: new Set()
|
|
917
|
+
frameReleased: new Set(),
|
|
918
|
+
mouseDown: new Set(),
|
|
919
|
+
pendingMousePressed: new Set(),
|
|
920
|
+
pendingMouseReleased: new Set(),
|
|
921
|
+
frameMousePressed: new Set(),
|
|
922
|
+
frameMouseReleased: new Set(),
|
|
923
|
+
pendingMouseDeltaX: 0,
|
|
924
|
+
pendingMouseDeltaY: 0,
|
|
925
|
+
frameMouseDeltaX: 0,
|
|
926
|
+
frameMouseDeltaY: 0
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
const assetState = {
|
|
930
|
+
bySourcePath: new Map(),
|
|
931
|
+
byOutputPath: new Map(),
|
|
932
|
+
loaded: new Map(),
|
|
933
|
+
storageFallback: new Map()
|
|
648
934
|
};
|
|
649
935
|
|
|
650
936
|
const runtime = {
|
|
@@ -658,11 +944,19 @@ const WEB_LOADER_SOURCE = `
|
|
|
658
944
|
width: normalizeCanvasSize(currentCanvasConfig.width, 1280),
|
|
659
945
|
height: normalizeCanvasSize(currentCanvasConfig.height, 720),
|
|
660
946
|
transformDepth: 0,
|
|
947
|
+
worldTransformActive: false,
|
|
948
|
+
cursorVisible: true,
|
|
949
|
+
cursorLocked: false,
|
|
661
950
|
listenersAttached: false,
|
|
662
951
|
keydownListener: null,
|
|
663
952
|
keyupListener: null,
|
|
953
|
+
focusListener: null,
|
|
664
954
|
blurListener: null,
|
|
665
|
-
resizeListener: null
|
|
955
|
+
resizeListener: null,
|
|
956
|
+
mousemoveListener: null,
|
|
957
|
+
mousedownListener: null,
|
|
958
|
+
mouseupListener: null,
|
|
959
|
+
wheelListener: null
|
|
666
960
|
};
|
|
667
961
|
|
|
668
962
|
function ensureStyleObject(node) {
|
|
@@ -681,6 +975,292 @@ const WEB_LOADER_SOURCE = `
|
|
|
681
975
|
return runtime.context2d;
|
|
682
976
|
}
|
|
683
977
|
|
|
978
|
+
function normalizeAssetKey(value) {
|
|
979
|
+
return sanitizeAssetSourcePath(value);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
function indexManifestAssets(manifest, rootUrl) {
|
|
983
|
+
currentManifest = manifest && typeof manifest === 'object' ? manifest : { assets: [] };
|
|
984
|
+
currentRootUrl = typeof rootUrl === 'string' && rootUrl.length > 0
|
|
985
|
+
? rootUrl.replace(/\\/$/, '')
|
|
986
|
+
: '.';
|
|
987
|
+
assetState.bySourcePath.clear();
|
|
988
|
+
assetState.byOutputPath.clear();
|
|
989
|
+
const entries = Array.isArray(currentManifest.assets) ? currentManifest.assets : [];
|
|
990
|
+
for (const entry of entries) {
|
|
991
|
+
if (!entry || typeof entry !== 'object') continue;
|
|
992
|
+
const outputPath = normalizePath(entry.path);
|
|
993
|
+
if (outputPath.length > 0) {
|
|
994
|
+
assetState.byOutputPath.set(outputPath, entry);
|
|
995
|
+
}
|
|
996
|
+
const sourcePath = normalizeAssetKey(entry.sourcePath || outputPath);
|
|
997
|
+
if (sourcePath.length > 0) {
|
|
998
|
+
assetState.bySourcePath.set(sourcePath, entry);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
function buildAssetUrl(entryPath) {
|
|
1004
|
+
const normalized = normalizePath(entryPath);
|
|
1005
|
+
const root = currentRootUrl && currentRootUrl.length > 0 ? currentRootUrl : '.';
|
|
1006
|
+
return root + '/' + normalized;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
function resolveAssetEntry(source) {
|
|
1010
|
+
const normalizedSource = normalizeAssetKey(source);
|
|
1011
|
+
if (normalizedSource.length === 0) return null;
|
|
1012
|
+
if (assetState.bySourcePath.has(normalizedSource)) {
|
|
1013
|
+
return assetState.bySourcePath.get(normalizedSource);
|
|
1014
|
+
}
|
|
1015
|
+
const outputPath = normalizePath(normalizedSource);
|
|
1016
|
+
if (assetState.byOutputPath.has(outputPath)) {
|
|
1017
|
+
return assetState.byOutputPath.get(outputPath);
|
|
1018
|
+
}
|
|
1019
|
+
return null;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
function resolveAssetSourcePath(source) {
|
|
1023
|
+
if (typeof source === 'string') {
|
|
1024
|
+
return normalizeAssetKey(source);
|
|
1025
|
+
}
|
|
1026
|
+
if (source && typeof source === 'object') {
|
|
1027
|
+
if (typeof source.sourcePath === 'string') return normalizeAssetKey(source.sourcePath);
|
|
1028
|
+
if (typeof source.path === 'string') return normalizeAssetKey(source.path);
|
|
1029
|
+
if (typeof source.name === 'string') return normalizeAssetKey(source.name);
|
|
1030
|
+
}
|
|
1031
|
+
return '';
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
function resolveLoadedAsset(source) {
|
|
1035
|
+
const key = resolveAssetSourcePath(source);
|
|
1036
|
+
if (key.length === 0) return null;
|
|
1037
|
+
return assetState.loaded.get(key) || null;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
function rememberLoadedAsset(sourcePath, handle) {
|
|
1041
|
+
const key = normalizeAssetKey(sourcePath);
|
|
1042
|
+
if (key.length === 0 || !handle || typeof handle !== 'object') return handle;
|
|
1043
|
+
handle.sourcePath = key;
|
|
1044
|
+
if (typeof handle.path !== 'string' || handle.path.length === 0) {
|
|
1045
|
+
handle.path = key;
|
|
1046
|
+
}
|
|
1047
|
+
assetState.loaded.set(key, handle);
|
|
1048
|
+
return handle;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
async function fetchAssetResponse(entry) {
|
|
1052
|
+
if (!entry || typeof entry !== 'object') return null;
|
|
1053
|
+
const assetUrl = buildAssetUrl(entry.path);
|
|
1054
|
+
let response;
|
|
1055
|
+
try {
|
|
1056
|
+
response = await fetch(assetUrl, { cache: 'force-cache' });
|
|
1057
|
+
} catch (_) {
|
|
1058
|
+
return null;
|
|
1059
|
+
}
|
|
1060
|
+
if (!response || response.ok !== true) {
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1063
|
+
return response;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
async function readAssetBytes(entry) {
|
|
1067
|
+
const response = await fetchAssetResponse(entry);
|
|
1068
|
+
if (!response || typeof response.arrayBuffer !== 'function') {
|
|
1069
|
+
return null;
|
|
1070
|
+
}
|
|
1071
|
+
try {
|
|
1072
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
1073
|
+
} catch (_) {
|
|
1074
|
+
return null;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
async function readAssetText(entry) {
|
|
1079
|
+
const response = await fetchAssetResponse(entry);
|
|
1080
|
+
if (!response || typeof response.text !== 'function') {
|
|
1081
|
+
return null;
|
|
1082
|
+
}
|
|
1083
|
+
try {
|
|
1084
|
+
return await response.text();
|
|
1085
|
+
} catch (_) {
|
|
1086
|
+
return null;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
async function loadImageHandle(sourcePath, entry) {
|
|
1091
|
+
const existing = resolveLoadedAsset(sourcePath);
|
|
1092
|
+
if (existing && existing.image) {
|
|
1093
|
+
return existing;
|
|
1094
|
+
}
|
|
1095
|
+
const ImageCtor = typeof globalRef.Image === 'function' ? globalRef.Image : null;
|
|
1096
|
+
const handle = existing || {
|
|
1097
|
+
kind: 'image',
|
|
1098
|
+
path: sourcePath,
|
|
1099
|
+
sourcePath: sourcePath,
|
|
1100
|
+
resolvedPath: entry && typeof entry.path === 'string' ? normalizePath(entry.path) : sourcePath,
|
|
1101
|
+
mediaType: entry && typeof entry.mediaType === 'string' ? entry.mediaType : 'image/png',
|
|
1102
|
+
image: null,
|
|
1103
|
+
width: 0,
|
|
1104
|
+
height: 0
|
|
1105
|
+
};
|
|
1106
|
+
if (!ImageCtor || !entry) {
|
|
1107
|
+
return rememberLoadedAsset(sourcePath, handle);
|
|
1108
|
+
}
|
|
1109
|
+
try {
|
|
1110
|
+
const image = await new Promise(function (resolvePromise, rejectPromise) {
|
|
1111
|
+
const node = new ImageCtor();
|
|
1112
|
+
node.onload = function () { resolvePromise(node); };
|
|
1113
|
+
node.onerror = function () { rejectPromise(new Error('image_load_failed')); };
|
|
1114
|
+
node.src = buildAssetUrl(entry.path);
|
|
1115
|
+
});
|
|
1116
|
+
handle.image = image;
|
|
1117
|
+
handle.width = normalizeCanvasSize(image.naturalWidth || image.width, 1);
|
|
1118
|
+
handle.height = normalizeCanvasSize(image.naturalHeight || image.height, 1);
|
|
1119
|
+
} catch (_) {}
|
|
1120
|
+
return rememberLoadedAsset(sourcePath, handle);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
function createBrowserSoundHandle(sourcePath, entry, bytes) {
|
|
1124
|
+
return rememberLoadedAsset(sourcePath, {
|
|
1125
|
+
kind: 'sound',
|
|
1126
|
+
path: sourcePath,
|
|
1127
|
+
sourcePath: sourcePath,
|
|
1128
|
+
resolvedPath: entry && typeof entry.path === 'string' ? normalizePath(entry.path) : sourcePath,
|
|
1129
|
+
mediaType: entry && typeof entry.mediaType === 'string' ? entry.mediaType : 'audio/ogg',
|
|
1130
|
+
bytes: bytes instanceof Uint8Array ? bytes : new Uint8Array(),
|
|
1131
|
+
playbackSupported: false,
|
|
1132
|
+
reasonCode: 'web_audio_playback_unsupported',
|
|
1133
|
+
detail: 'Browser runtime resolves sound assets but does not support aura.audio playback. [reason:web_audio_playback_unsupported]'
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
async function loadAssetRecord(source) {
|
|
1138
|
+
if (Array.isArray(source)) {
|
|
1139
|
+
const loaded = [];
|
|
1140
|
+
for (const entry of source) {
|
|
1141
|
+
const next = await loadAssetRecord(entry);
|
|
1142
|
+
if (next) loaded.push(next);
|
|
1143
|
+
}
|
|
1144
|
+
return loaded;
|
|
1145
|
+
}
|
|
1146
|
+
const sourcePath = resolveAssetSourcePath(source);
|
|
1147
|
+
if (sourcePath.length === 0) return null;
|
|
1148
|
+
const existing = resolveLoadedAsset(sourcePath);
|
|
1149
|
+
if (existing) return existing;
|
|
1150
|
+
const entry = resolveAssetEntry(sourcePath);
|
|
1151
|
+
if (!entry) return null;
|
|
1152
|
+
if (isImageMediaType(entry.mediaType)) {
|
|
1153
|
+
return await loadImageHandle(sourcePath, entry);
|
|
1154
|
+
}
|
|
1155
|
+
const bytes = await readAssetBytes(entry);
|
|
1156
|
+
if (entry.mediaType && entry.mediaType.startsWith('audio/')) {
|
|
1157
|
+
return createBrowserSoundHandle(sourcePath, entry, bytes);
|
|
1158
|
+
}
|
|
1159
|
+
if (!bytes) {
|
|
1160
|
+
return rememberLoadedAsset(sourcePath, {
|
|
1161
|
+
kind: 'asset',
|
|
1162
|
+
path: sourcePath,
|
|
1163
|
+
sourcePath: sourcePath,
|
|
1164
|
+
resolvedPath: normalizePath(entry.path),
|
|
1165
|
+
mediaType: entry.mediaType,
|
|
1166
|
+
bytes: new Uint8Array()
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
const handle = {
|
|
1170
|
+
kind: 'asset',
|
|
1171
|
+
path: sourcePath,
|
|
1172
|
+
sourcePath: sourcePath,
|
|
1173
|
+
resolvedPath: normalizePath(entry.path),
|
|
1174
|
+
mediaType: entry.mediaType,
|
|
1175
|
+
bytes: bytes
|
|
1176
|
+
};
|
|
1177
|
+
if (entry.mediaType === 'application/json') {
|
|
1178
|
+
const text = typeof TextDecoder === 'function'
|
|
1179
|
+
? new TextDecoder('utf-8').decode(bytes)
|
|
1180
|
+
: String.fromCharCode.apply(null, Array.from(bytes));
|
|
1181
|
+
handle.text = text;
|
|
1182
|
+
try {
|
|
1183
|
+
handle.json = JSON.parse(text);
|
|
1184
|
+
} catch (_) {
|
|
1185
|
+
handle.json = null;
|
|
1186
|
+
}
|
|
1187
|
+
} else if (typeof entry.mediaType === 'string' && entry.mediaType.startsWith('text/')) {
|
|
1188
|
+
handle.text = typeof TextDecoder === 'function'
|
|
1189
|
+
? new TextDecoder('utf-8').decode(bytes)
|
|
1190
|
+
: String.fromCharCode.apply(null, Array.from(bytes));
|
|
1191
|
+
}
|
|
1192
|
+
return rememberLoadedAsset(sourcePath, handle);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
function normalizeMousePosition(event) {
|
|
1196
|
+
const source = event && typeof event === 'object' ? event : {};
|
|
1197
|
+
if (Number.isFinite(Number(source.offsetX)) && Number.isFinite(Number(source.offsetY))) {
|
|
1198
|
+
return {
|
|
1199
|
+
x: Number(source.offsetX),
|
|
1200
|
+
y: Number(source.offsetY)
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
const canvas = runtime.canvas;
|
|
1204
|
+
const rect = canvas && typeof canvas.getBoundingClientRect === 'function'
|
|
1205
|
+
? canvas.getBoundingClientRect()
|
|
1206
|
+
: null;
|
|
1207
|
+
const clientX = toFinite(source.clientX, auraRef.input.mouse.x);
|
|
1208
|
+
const clientY = toFinite(source.clientY, auraRef.input.mouse.y);
|
|
1209
|
+
if (rect) {
|
|
1210
|
+
return {
|
|
1211
|
+
x: clientX - toFinite(rect.left, 0),
|
|
1212
|
+
y: clientY - toFinite(rect.top, 0)
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
return {
|
|
1216
|
+
x: clientX,
|
|
1217
|
+
y: clientY
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
function syncMousePosition(event) {
|
|
1222
|
+
const point = normalizeMousePosition(event);
|
|
1223
|
+
const movementX = Number(event && event.movementX);
|
|
1224
|
+
const movementY = Number(event && event.movementY);
|
|
1225
|
+
const deltaX = Number.isFinite(movementX) ? movementX : point.x - auraRef.input.mouse.x;
|
|
1226
|
+
const deltaY = Number.isFinite(movementY) ? movementY : point.y - auraRef.input.mouse.y;
|
|
1227
|
+
inputState.pendingMouseDeltaX += deltaX;
|
|
1228
|
+
inputState.pendingMouseDeltaY += deltaY;
|
|
1229
|
+
auraRef.input.mouse.x = point.x;
|
|
1230
|
+
auraRef.input.mouse.y = point.y;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
function clearMouseDeltaState() {
|
|
1234
|
+
inputState.pendingMouseDeltaX = 0;
|
|
1235
|
+
inputState.pendingMouseDeltaY = 0;
|
|
1236
|
+
inputState.frameMouseDeltaX = 0;
|
|
1237
|
+
inputState.frameMouseDeltaY = 0;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
function clearTransientInputState() {
|
|
1241
|
+
inputState.pendingPressed.clear();
|
|
1242
|
+
inputState.pendingReleased.clear();
|
|
1243
|
+
inputState.framePressed.clear();
|
|
1244
|
+
inputState.frameReleased.clear();
|
|
1245
|
+
inputState.pendingMousePressed.clear();
|
|
1246
|
+
inputState.pendingMouseReleased.clear();
|
|
1247
|
+
inputState.frameMousePressed.clear();
|
|
1248
|
+
inputState.frameMouseReleased.clear();
|
|
1249
|
+
clearMouseDeltaState();
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
function clearHeldInputState() {
|
|
1253
|
+
inputState.down.clear();
|
|
1254
|
+
inputState.mouseDown.clear();
|
|
1255
|
+
clearTransientInputState();
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
function applyCursorAppearance() {
|
|
1259
|
+
const style = ensureStyleObject(runtime.canvas);
|
|
1260
|
+
if (!style) return;
|
|
1261
|
+
style.cursor = (!runtime.cursorVisible || runtime.cursorLocked) ? 'none' : 'default';
|
|
1262
|
+
}
|
|
1263
|
+
|
|
684
1264
|
function syncCanvasSize(notifyResize) {
|
|
685
1265
|
let width = runtime.configuredWidth;
|
|
686
1266
|
let height = runtime.configuredHeight;
|
|
@@ -736,11 +1316,54 @@ const WEB_LOADER_SOURCE = `
|
|
|
736
1316
|
}
|
|
737
1317
|
}
|
|
738
1318
|
runtime.transformDepth = 0;
|
|
1319
|
+
runtime.worldTransformActive = false;
|
|
739
1320
|
ctx.globalAlpha = 1;
|
|
740
1321
|
ctx.textAlign = 'left';
|
|
741
1322
|
ctx.textBaseline = 'top';
|
|
742
1323
|
}
|
|
743
1324
|
|
|
1325
|
+
function applyWorldTransform() {
|
|
1326
|
+
const ctx = ensureCanvasContext();
|
|
1327
|
+
if (!ctx || runtime.worldTransformActive) return ctx;
|
|
1328
|
+
const camera = auraRef.camera && typeof auraRef.camera === 'object' ? auraRef.camera : null;
|
|
1329
|
+
if (camera) {
|
|
1330
|
+
const zoom = normalizePositiveNumber(camera.zoom, 1);
|
|
1331
|
+
const rotation = Number(camera.rotation) || 0;
|
|
1332
|
+
const x = Number(camera.x) || 0;
|
|
1333
|
+
const y = Number(camera.y) || 0;
|
|
1334
|
+
if (typeof ctx.scale === 'function' && zoom !== 1) {
|
|
1335
|
+
ctx.scale(zoom, zoom);
|
|
1336
|
+
}
|
|
1337
|
+
if (typeof ctx.rotate === 'function' && rotation !== 0) {
|
|
1338
|
+
ctx.rotate(rotation);
|
|
1339
|
+
}
|
|
1340
|
+
if (typeof ctx.translate === 'function' && (x !== 0 || y !== 0)) {
|
|
1341
|
+
ctx.translate(-x, -y);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
runtime.worldTransformActive = true;
|
|
1345
|
+
return ctx;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
function ensureWorldTransform() {
|
|
1349
|
+
const ctx = ensureCanvasContext();
|
|
1350
|
+
if (!ctx) return null;
|
|
1351
|
+
return runtime.worldTransformActive ? ctx : applyWorldTransform();
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
function normalizeTextOptions(sizeOrOptions, colorMaybe) {
|
|
1355
|
+
if (sizeOrOptions && typeof sizeOrOptions === 'object' && !Array.isArray(sizeOrOptions)) {
|
|
1356
|
+
return sizeOrOptions;
|
|
1357
|
+
}
|
|
1358
|
+
if (Number.isFinite(Number(sizeOrOptions))) {
|
|
1359
|
+
return {
|
|
1360
|
+
size: Number(sizeOrOptions),
|
|
1361
|
+
color: colorMaybe
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
return {};
|
|
1365
|
+
}
|
|
1366
|
+
|
|
744
1367
|
function applyFont(options) {
|
|
745
1368
|
const ctx = ensureCanvasContext();
|
|
746
1369
|
const source = options && typeof options === 'object' ? options : {};
|
|
@@ -756,6 +1379,505 @@ const WEB_LOADER_SOURCE = `
|
|
|
756
1379
|
return { size, align: normalizeTextAlign(source.align) };
|
|
757
1380
|
}
|
|
758
1381
|
|
|
1382
|
+
function withScreenSpace(callback) {
|
|
1383
|
+
const ctx = ensureCanvasContext();
|
|
1384
|
+
if (!ctx || typeof callback !== 'function') return null;
|
|
1385
|
+
if (typeof ctx.save === 'function') {
|
|
1386
|
+
ctx.save();
|
|
1387
|
+
}
|
|
1388
|
+
if (typeof ctx.setTransform === 'function') {
|
|
1389
|
+
ctx.setTransform(runtime.pixelRatio, 0, 0, runtime.pixelRatio, 0, 0);
|
|
1390
|
+
} else {
|
|
1391
|
+
if (typeof ctx.resetTransform === 'function') {
|
|
1392
|
+
ctx.resetTransform();
|
|
1393
|
+
}
|
|
1394
|
+
if (typeof ctx.scale === 'function') {
|
|
1395
|
+
ctx.scale(runtime.pixelRatio, runtime.pixelRatio);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
try {
|
|
1399
|
+
return callback(ctx);
|
|
1400
|
+
} finally {
|
|
1401
|
+
if (typeof ctx.restore === 'function') {
|
|
1402
|
+
ctx.restore();
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
function resolveStorageBackend() {
|
|
1408
|
+
return globalRef.localStorage && typeof globalRef.localStorage.getItem === 'function'
|
|
1409
|
+
? globalRef.localStorage
|
|
1410
|
+
: null;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
function storageKey(key) {
|
|
1414
|
+
return 'aurajs:' + String(key || '');
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
function readStorage(key) {
|
|
1418
|
+
const normalizedKey = String(key || '');
|
|
1419
|
+
if (normalizedKey.length === 0) return null;
|
|
1420
|
+
const backend = resolveStorageBackend();
|
|
1421
|
+
const namespaced = storageKey(normalizedKey);
|
|
1422
|
+
let raw = null;
|
|
1423
|
+
if (backend) {
|
|
1424
|
+
try {
|
|
1425
|
+
raw = backend.getItem(namespaced);
|
|
1426
|
+
} catch (_) {
|
|
1427
|
+
raw = null;
|
|
1428
|
+
}
|
|
1429
|
+
} else if (assetState.storageFallback.has(namespaced)) {
|
|
1430
|
+
raw = assetState.storageFallback.get(namespaced);
|
|
1431
|
+
}
|
|
1432
|
+
if (raw == null) return null;
|
|
1433
|
+
try {
|
|
1434
|
+
return JSON.parse(raw);
|
|
1435
|
+
} catch (_) {
|
|
1436
|
+
return raw;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
function writeStorage(key, value) {
|
|
1441
|
+
const normalizedKey = String(key || '');
|
|
1442
|
+
if (normalizedKey.length === 0) return false;
|
|
1443
|
+
const payload = JSON.stringify(value);
|
|
1444
|
+
const backend = resolveStorageBackend();
|
|
1445
|
+
const namespaced = storageKey(normalizedKey);
|
|
1446
|
+
if (backend) {
|
|
1447
|
+
try {
|
|
1448
|
+
backend.setItem(namespaced, payload);
|
|
1449
|
+
return true;
|
|
1450
|
+
} catch (_) {
|
|
1451
|
+
return false;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
assetState.storageFallback.set(namespaced, payload);
|
|
1455
|
+
return true;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
function deleteStorage(key) {
|
|
1459
|
+
const normalizedKey = String(key || '');
|
|
1460
|
+
if (normalizedKey.length === 0) return false;
|
|
1461
|
+
const namespaced = storageKey(normalizedKey);
|
|
1462
|
+
const backend = resolveStorageBackend();
|
|
1463
|
+
if (backend) {
|
|
1464
|
+
try {
|
|
1465
|
+
backend.removeItem(namespaced);
|
|
1466
|
+
return true;
|
|
1467
|
+
} catch (_) {
|
|
1468
|
+
return false;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
return assetState.storageFallback.delete(namespaced);
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
const camera = auraRef.camera && typeof auraRef.camera === 'object' ? auraRef.camera : {};
|
|
1475
|
+
let cameraBaseX = Number(camera.x) || 0;
|
|
1476
|
+
let cameraBaseY = Number(camera.y) || 0;
|
|
1477
|
+
let cameraBaseZoom = normalizePositiveNumber(camera.zoom, 1);
|
|
1478
|
+
let cameraBaseRotation = Number(camera.rotation) || 0;
|
|
1479
|
+
let cameraShakeX = 0;
|
|
1480
|
+
let cameraShakeY = 0;
|
|
1481
|
+
let cameraFollowState = null;
|
|
1482
|
+
let cameraDeadzone = null;
|
|
1483
|
+
let cameraBounds = null;
|
|
1484
|
+
let nextCameraEffectId = 1;
|
|
1485
|
+
let nextCameraListenerId = 1;
|
|
1486
|
+
const cameraEffects = [];
|
|
1487
|
+
const cameraEffectListeners = [];
|
|
1488
|
+
|
|
1489
|
+
function applyCameraBounds() {
|
|
1490
|
+
if (!cameraBounds) return;
|
|
1491
|
+
const maxX = cameraBounds.x + cameraBounds.width;
|
|
1492
|
+
const maxY = cameraBounds.y + cameraBounds.height;
|
|
1493
|
+
cameraBaseX = Math.max(cameraBounds.x, Math.min(cameraBaseX, maxX));
|
|
1494
|
+
cameraBaseY = Math.max(cameraBounds.y, Math.min(cameraBaseY, maxY));
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
function normalizeFollowOptions(options) {
|
|
1498
|
+
if (options == null) {
|
|
1499
|
+
return {
|
|
1500
|
+
lerpX: 1,
|
|
1501
|
+
lerpY: 1,
|
|
1502
|
+
offsetX: 0,
|
|
1503
|
+
offsetY: 0
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
if (!isObject(options)) return null;
|
|
1507
|
+
return {
|
|
1508
|
+
lerpX: clamp01(options.lerpX),
|
|
1509
|
+
lerpY: clamp01(options.lerpY),
|
|
1510
|
+
offsetX: toFinite(options.offsetX, 0),
|
|
1511
|
+
offsetY: toFinite(options.offsetY, 0)
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
function normalizeDeadzone(value) {
|
|
1516
|
+
const input = isObject(value) ? value : null;
|
|
1517
|
+
const zoneWidth = toFinite(input && input.width, Number.NaN);
|
|
1518
|
+
const zoneHeight = toFinite(input && input.height, Number.NaN);
|
|
1519
|
+
if (!(zoneWidth > 0) || !(zoneHeight > 0)) return null;
|
|
1520
|
+
return {
|
|
1521
|
+
x: toFinite(input && input.x, 0),
|
|
1522
|
+
y: toFinite(input && input.y, 0),
|
|
1523
|
+
width: zoneWidth,
|
|
1524
|
+
height: zoneHeight
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
function normalizeBounds(value) {
|
|
1529
|
+
const input = isObject(value) ? value : null;
|
|
1530
|
+
const zoneWidth = toFinite(input && input.width, Number.NaN);
|
|
1531
|
+
const zoneHeight = toFinite(input && input.height, Number.NaN);
|
|
1532
|
+
if (!(zoneWidth >= 0) || !(zoneHeight >= 0)) return null;
|
|
1533
|
+
return {
|
|
1534
|
+
x: toFinite(input && input.x, 0),
|
|
1535
|
+
y: toFinite(input && input.y, 0),
|
|
1536
|
+
width: zoneWidth,
|
|
1537
|
+
height: zoneHeight
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
function resolveFollowTarget(target) {
|
|
1542
|
+
let source = target;
|
|
1543
|
+
if (typeof source === 'function') {
|
|
1544
|
+
try {
|
|
1545
|
+
source = source();
|
|
1546
|
+
} catch (_) {
|
|
1547
|
+
return null;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
if (!isObject(source)) return null;
|
|
1551
|
+
const x = toFinite(source.x, Number.NaN);
|
|
1552
|
+
const y = toFinite(source.y, Number.NaN);
|
|
1553
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return null;
|
|
1554
|
+
return { x: x, y: y };
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
function emitCameraEffectEvent(event) {
|
|
1558
|
+
if (cameraEffectListeners.length === 0) return;
|
|
1559
|
+
const ordered = cameraEffectListeners.slice().sort(function (a, b) {
|
|
1560
|
+
return (a.order - b.order) || (a.id - b.id);
|
|
1561
|
+
});
|
|
1562
|
+
for (const listener of ordered) {
|
|
1563
|
+
try {
|
|
1564
|
+
listener.callback(event);
|
|
1565
|
+
} catch (_) {}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
Object.defineProperties(camera, {
|
|
1570
|
+
x: {
|
|
1571
|
+
enumerable: true,
|
|
1572
|
+
configurable: false,
|
|
1573
|
+
get: function () { return cameraBaseX + cameraShakeX; },
|
|
1574
|
+
set: function (value) {
|
|
1575
|
+
const numeric = Number(value);
|
|
1576
|
+
if (Number.isFinite(numeric)) cameraBaseX = numeric;
|
|
1577
|
+
}
|
|
1578
|
+
},
|
|
1579
|
+
y: {
|
|
1580
|
+
enumerable: true,
|
|
1581
|
+
configurable: false,
|
|
1582
|
+
get: function () { return cameraBaseY + cameraShakeY; },
|
|
1583
|
+
set: function (value) {
|
|
1584
|
+
const numeric = Number(value);
|
|
1585
|
+
if (Number.isFinite(numeric)) cameraBaseY = numeric;
|
|
1586
|
+
}
|
|
1587
|
+
},
|
|
1588
|
+
zoom: {
|
|
1589
|
+
enumerable: true,
|
|
1590
|
+
configurable: false,
|
|
1591
|
+
get: function () { return cameraBaseZoom; },
|
|
1592
|
+
set: function (value) {
|
|
1593
|
+
const numeric = Number(value);
|
|
1594
|
+
if (Number.isFinite(numeric) && numeric > 0) cameraBaseZoom = numeric;
|
|
1595
|
+
}
|
|
1596
|
+
},
|
|
1597
|
+
rotation: {
|
|
1598
|
+
enumerable: true,
|
|
1599
|
+
configurable: false,
|
|
1600
|
+
get: function () { return cameraBaseRotation; },
|
|
1601
|
+
set: function (value) {
|
|
1602
|
+
const numeric = Number(value);
|
|
1603
|
+
if (Number.isFinite(numeric)) cameraBaseRotation = numeric;
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
});
|
|
1607
|
+
|
|
1608
|
+
camera.getState = function () {
|
|
1609
|
+
return {
|
|
1610
|
+
x: cameraBaseX + cameraShakeX,
|
|
1611
|
+
y: cameraBaseY + cameraShakeY,
|
|
1612
|
+
zoom: cameraBaseZoom,
|
|
1613
|
+
rotation: cameraBaseRotation,
|
|
1614
|
+
following: !!cameraFollowState,
|
|
1615
|
+
activeEffects: cameraEffects.length,
|
|
1616
|
+
deadzone: cameraDeadzone ? { x: cameraDeadzone.x, y: cameraDeadzone.y, width: cameraDeadzone.width, height: cameraDeadzone.height } : null,
|
|
1617
|
+
bounds: cameraBounds ? { x: cameraBounds.x, y: cameraBounds.y, width: cameraBounds.width, height: cameraBounds.height } : null
|
|
1618
|
+
};
|
|
1619
|
+
};
|
|
1620
|
+
|
|
1621
|
+
camera.follow = function (target, options) {
|
|
1622
|
+
if (!(typeof target === 'function' || isObject(target))) {
|
|
1623
|
+
return { ok: false, reasonCode: 'invalid_follow_target' };
|
|
1624
|
+
}
|
|
1625
|
+
const normalized = normalizeFollowOptions(options);
|
|
1626
|
+
if (!normalized) return { ok: false, reasonCode: 'invalid_follow_options' };
|
|
1627
|
+
cameraFollowState = {
|
|
1628
|
+
target: target,
|
|
1629
|
+
lerpX: normalized.lerpX,
|
|
1630
|
+
lerpY: normalized.lerpY,
|
|
1631
|
+
offsetX: normalized.offsetX,
|
|
1632
|
+
offsetY: normalized.offsetY
|
|
1633
|
+
};
|
|
1634
|
+
return { ok: true, reasonCode: 'camera_follow_started' };
|
|
1635
|
+
};
|
|
1636
|
+
|
|
1637
|
+
camera.stopFollow = function () {
|
|
1638
|
+
const stopped = !!cameraFollowState;
|
|
1639
|
+
cameraFollowState = null;
|
|
1640
|
+
return { ok: true, stopped: stopped, reasonCode: 'camera_follow_stopped' };
|
|
1641
|
+
};
|
|
1642
|
+
|
|
1643
|
+
camera.setDeadzone = function (value, maybeHeight) {
|
|
1644
|
+
const normalized = isObject(value)
|
|
1645
|
+
? normalizeDeadzone(value)
|
|
1646
|
+
: normalizeDeadzone({ width: value, height: maybeHeight });
|
|
1647
|
+
if (!normalized) return { ok: false, reasonCode: 'invalid_deadzone' };
|
|
1648
|
+
cameraDeadzone = normalized;
|
|
1649
|
+
return { ok: true, reasonCode: 'camera_deadzone_set' };
|
|
1650
|
+
};
|
|
1651
|
+
|
|
1652
|
+
camera.clearDeadzone = function () {
|
|
1653
|
+
cameraDeadzone = null;
|
|
1654
|
+
return { ok: true, reasonCode: 'camera_deadzone_cleared' };
|
|
1655
|
+
};
|
|
1656
|
+
|
|
1657
|
+
camera.setBounds = function (xOrBounds, y, boundsWidth, boundsHeight) {
|
|
1658
|
+
const normalized = isObject(xOrBounds)
|
|
1659
|
+
? normalizeBounds(xOrBounds)
|
|
1660
|
+
: normalizeBounds({ x: xOrBounds, y: y, width: boundsWidth, height: boundsHeight });
|
|
1661
|
+
if (!normalized) return { ok: false, reasonCode: 'invalid_bounds' };
|
|
1662
|
+
cameraBounds = normalized;
|
|
1663
|
+
applyCameraBounds();
|
|
1664
|
+
return { ok: true, reasonCode: 'camera_bounds_set' };
|
|
1665
|
+
};
|
|
1666
|
+
|
|
1667
|
+
camera.clearBounds = function () {
|
|
1668
|
+
cameraBounds = null;
|
|
1669
|
+
return { ok: true, reasonCode: 'camera_bounds_cleared' };
|
|
1670
|
+
};
|
|
1671
|
+
|
|
1672
|
+
camera.pan = function (x, y, options) {
|
|
1673
|
+
const targetX = Number(x);
|
|
1674
|
+
const targetY = Number(y);
|
|
1675
|
+
if (!Number.isFinite(targetX) || !Number.isFinite(targetY)) {
|
|
1676
|
+
return { ok: false, reasonCode: 'invalid_pan_target' };
|
|
1677
|
+
}
|
|
1678
|
+
if (options != null && !isObject(options)) return { ok: false, reasonCode: 'invalid_pan_options' };
|
|
1679
|
+
const duration = toPositive(options && options.duration, 0.25);
|
|
1680
|
+
if (!(duration > 0)) return { ok: false, reasonCode: 'invalid_pan_duration' };
|
|
1681
|
+
const effectId = nextCameraEffectId++;
|
|
1682
|
+
cameraEffects.push({
|
|
1683
|
+
id: effectId,
|
|
1684
|
+
type: 'pan',
|
|
1685
|
+
duration: duration,
|
|
1686
|
+
elapsed: 0,
|
|
1687
|
+
startX: cameraBaseX,
|
|
1688
|
+
startY: cameraBaseY,
|
|
1689
|
+
targetX: targetX,
|
|
1690
|
+
targetY: targetY
|
|
1691
|
+
});
|
|
1692
|
+
return { ok: true, effectId: effectId, reasonCode: 'camera_pan_started' };
|
|
1693
|
+
};
|
|
1694
|
+
camera.panTo = camera.pan;
|
|
1695
|
+
|
|
1696
|
+
camera.zoomTo = function (value, options) {
|
|
1697
|
+
const targetZoom = Number(value);
|
|
1698
|
+
if (!Number.isFinite(targetZoom) || !(targetZoom > 0)) {
|
|
1699
|
+
return { ok: false, reasonCode: 'invalid_zoom_target' };
|
|
1700
|
+
}
|
|
1701
|
+
if (options != null && !isObject(options)) return { ok: false, reasonCode: 'invalid_zoom_options' };
|
|
1702
|
+
const duration = toPositive(options && options.duration, 0.25);
|
|
1703
|
+
if (!(duration > 0)) return { ok: false, reasonCode: 'invalid_zoom_duration' };
|
|
1704
|
+
const effectId = nextCameraEffectId++;
|
|
1705
|
+
cameraEffects.push({
|
|
1706
|
+
id: effectId,
|
|
1707
|
+
type: 'zoom',
|
|
1708
|
+
duration: duration,
|
|
1709
|
+
elapsed: 0,
|
|
1710
|
+
startZoom: cameraBaseZoom,
|
|
1711
|
+
targetZoom: targetZoom
|
|
1712
|
+
});
|
|
1713
|
+
return { ok: true, effectId: effectId, reasonCode: 'camera_zoom_started' };
|
|
1714
|
+
};
|
|
1715
|
+
|
|
1716
|
+
camera.rotateTo = function (value, options) {
|
|
1717
|
+
const targetRotation = Number(value);
|
|
1718
|
+
if (!Number.isFinite(targetRotation)) {
|
|
1719
|
+
return { ok: false, reasonCode: 'invalid_rotation_target' };
|
|
1720
|
+
}
|
|
1721
|
+
if (options != null && !isObject(options)) return { ok: false, reasonCode: 'invalid_rotation_options' };
|
|
1722
|
+
const duration = toPositive(options && options.duration, 0.25);
|
|
1723
|
+
if (!(duration > 0)) return { ok: false, reasonCode: 'invalid_rotation_duration' };
|
|
1724
|
+
const effectId = nextCameraEffectId++;
|
|
1725
|
+
cameraEffects.push({
|
|
1726
|
+
id: effectId,
|
|
1727
|
+
type: 'rotate',
|
|
1728
|
+
duration: duration,
|
|
1729
|
+
elapsed: 0,
|
|
1730
|
+
startRotation: cameraBaseRotation,
|
|
1731
|
+
targetRotation: targetRotation
|
|
1732
|
+
});
|
|
1733
|
+
return { ok: true, effectId: effectId, reasonCode: 'camera_rotation_started' };
|
|
1734
|
+
};
|
|
1735
|
+
|
|
1736
|
+
camera.shake = function (options) {
|
|
1737
|
+
const source = options == null ? {} : options;
|
|
1738
|
+
if (!isObject(source)) return { ok: false, reasonCode: 'invalid_shake_options' };
|
|
1739
|
+
const sharedIntensity = Number.isFinite(Number(source.intensity))
|
|
1740
|
+
? Number(source.intensity)
|
|
1741
|
+
: null;
|
|
1742
|
+
const intensityX = toFinite(source.intensityX, sharedIntensity != null ? sharedIntensity : 6);
|
|
1743
|
+
const intensityY = toFinite(source.intensityY, sharedIntensity != null ? sharedIntensity : 6);
|
|
1744
|
+
if (!(intensityX >= 0) || !(intensityY >= 0)) {
|
|
1745
|
+
return { ok: false, reasonCode: 'invalid_shake_intensity' };
|
|
1746
|
+
}
|
|
1747
|
+
const duration = toPositive(source.duration, 0.3);
|
|
1748
|
+
if (!(duration > 0)) return { ok: false, reasonCode: 'invalid_shake_duration' };
|
|
1749
|
+
const frequency = toPositive(source.frequency, 30);
|
|
1750
|
+
if (!(frequency > 0)) return { ok: false, reasonCode: 'invalid_shake_frequency' };
|
|
1751
|
+
const effectId = nextCameraEffectId++;
|
|
1752
|
+
cameraEffects.push({
|
|
1753
|
+
id: effectId,
|
|
1754
|
+
type: 'shake',
|
|
1755
|
+
duration: duration,
|
|
1756
|
+
elapsed: 0,
|
|
1757
|
+
intensityX: intensityX,
|
|
1758
|
+
intensityY: intensityY,
|
|
1759
|
+
frequency: frequency,
|
|
1760
|
+
seed: effectId * 0.61803398875
|
|
1761
|
+
});
|
|
1762
|
+
return { ok: true, effectId: effectId, reasonCode: 'camera_shake_started' };
|
|
1763
|
+
};
|
|
1764
|
+
|
|
1765
|
+
camera.clearEffects = function () {
|
|
1766
|
+
const cleared = cameraEffects.length;
|
|
1767
|
+
cameraEffects.length = 0;
|
|
1768
|
+
cameraShakeX = 0;
|
|
1769
|
+
cameraShakeY = 0;
|
|
1770
|
+
return { ok: true, cleared: cleared, reasonCode: 'camera_effects_cleared' };
|
|
1771
|
+
};
|
|
1772
|
+
|
|
1773
|
+
camera.onEffectComplete = function (callback, order) {
|
|
1774
|
+
if (typeof callback !== 'function') {
|
|
1775
|
+
return { ok: false, reasonCode: 'invalid_effect_callback' };
|
|
1776
|
+
}
|
|
1777
|
+
const listener = {
|
|
1778
|
+
id: nextCameraListenerId++,
|
|
1779
|
+
callback: callback,
|
|
1780
|
+
order: Number.isFinite(Number(order)) ? Number(order) : 0
|
|
1781
|
+
};
|
|
1782
|
+
cameraEffectListeners.push(listener);
|
|
1783
|
+
return { ok: true, listenerId: listener.id, reasonCode: 'camera_effect_listener_registered' };
|
|
1784
|
+
};
|
|
1785
|
+
|
|
1786
|
+
camera.offEffectComplete = function (listenerId) {
|
|
1787
|
+
if (!Number.isInteger(listenerId) || listenerId <= 0) return false;
|
|
1788
|
+
const index = cameraEffectListeners.findIndex(function (entry) {
|
|
1789
|
+
return entry.id === listenerId;
|
|
1790
|
+
});
|
|
1791
|
+
if (index < 0) return false;
|
|
1792
|
+
cameraEffectListeners.splice(index, 1);
|
|
1793
|
+
return true;
|
|
1794
|
+
};
|
|
1795
|
+
|
|
1796
|
+
camera.update = function (dt) {
|
|
1797
|
+
const delta = Number(dt);
|
|
1798
|
+
if (!Number.isFinite(delta) || !(delta > 0)) {
|
|
1799
|
+
return { ok: false, reasonCode: 'invalid_dt' };
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
cameraShakeX = 0;
|
|
1803
|
+
cameraShakeY = 0;
|
|
1804
|
+
|
|
1805
|
+
if (cameraFollowState) {
|
|
1806
|
+
const targetPoint = resolveFollowTarget(cameraFollowState.target);
|
|
1807
|
+
if (targetPoint) {
|
|
1808
|
+
let targetX = targetPoint.x + cameraFollowState.offsetX;
|
|
1809
|
+
let targetY = targetPoint.y + cameraFollowState.offsetY;
|
|
1810
|
+
|
|
1811
|
+
if (cameraDeadzone) {
|
|
1812
|
+
const left = cameraBaseX + cameraDeadzone.x;
|
|
1813
|
+
const right = left + cameraDeadzone.width;
|
|
1814
|
+
const top = cameraBaseY + cameraDeadzone.y;
|
|
1815
|
+
const bottom = top + cameraDeadzone.height;
|
|
1816
|
+
|
|
1817
|
+
if (targetX < left) targetX = targetX - cameraDeadzone.x;
|
|
1818
|
+
else if (targetX > right) targetX = targetX - cameraDeadzone.x - cameraDeadzone.width;
|
|
1819
|
+
else targetX = cameraBaseX;
|
|
1820
|
+
|
|
1821
|
+
if (targetY < top) targetY = targetY - cameraDeadzone.y;
|
|
1822
|
+
else if (targetY > bottom) targetY = targetY - cameraDeadzone.y - cameraDeadzone.height;
|
|
1823
|
+
else targetY = cameraBaseY;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
cameraBaseX += (targetX - cameraBaseX) * cameraFollowState.lerpX;
|
|
1827
|
+
cameraBaseY += (targetY - cameraBaseY) * cameraFollowState.lerpY;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
const completedEffects = [];
|
|
1832
|
+
for (const effect of cameraEffects) {
|
|
1833
|
+
effect.elapsed += delta;
|
|
1834
|
+
const progress = effect.duration <= 0 ? 1 : Math.min(effect.elapsed / effect.duration, 1);
|
|
1835
|
+
if (effect.type === 'pan') {
|
|
1836
|
+
cameraBaseX = effect.startX + ((effect.targetX - effect.startX) * progress);
|
|
1837
|
+
cameraBaseY = effect.startY + ((effect.targetY - effect.startY) * progress);
|
|
1838
|
+
} else if (effect.type === 'zoom') {
|
|
1839
|
+
cameraBaseZoom = effect.startZoom + ((effect.targetZoom - effect.startZoom) * progress);
|
|
1840
|
+
} else if (effect.type === 'rotate') {
|
|
1841
|
+
cameraBaseRotation = effect.startRotation + ((effect.targetRotation - effect.startRotation) * progress);
|
|
1842
|
+
} else if (effect.type === 'shake') {
|
|
1843
|
+
const amplitude = 1 - progress;
|
|
1844
|
+
const angle = (effect.seed + (effect.elapsed * effect.frequency)) * 6.283185307179586;
|
|
1845
|
+
cameraShakeX += Math.sin(angle) * effect.intensityX * amplitude;
|
|
1846
|
+
cameraShakeY += Math.cos(angle * 1.17) * effect.intensityY * amplitude;
|
|
1847
|
+
}
|
|
1848
|
+
if (progress >= 1) completedEffects.push(effect);
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
if (completedEffects.length > 0) {
|
|
1852
|
+
for (const completed of completedEffects) {
|
|
1853
|
+
const index = cameraEffects.indexOf(completed);
|
|
1854
|
+
if (index >= 0) cameraEffects.splice(index, 1);
|
|
1855
|
+
}
|
|
1856
|
+
completedEffects.sort(function (a, b) { return a.id - b.id; });
|
|
1857
|
+
for (const completed of completedEffects) {
|
|
1858
|
+
emitCameraEffectEvent({
|
|
1859
|
+
type: 'effect_complete',
|
|
1860
|
+
effectType: completed.type,
|
|
1861
|
+
effectId: completed.id,
|
|
1862
|
+
reasonCode: 'camera_effect_complete'
|
|
1863
|
+
});
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
applyCameraBounds();
|
|
1868
|
+
|
|
1869
|
+
return {
|
|
1870
|
+
ok: true,
|
|
1871
|
+
reasonCode: 'camera_updated',
|
|
1872
|
+
x: cameraBaseX + cameraShakeX,
|
|
1873
|
+
y: cameraBaseY + cameraShakeY,
|
|
1874
|
+
zoom: cameraBaseZoom,
|
|
1875
|
+
rotation: cameraBaseRotation,
|
|
1876
|
+
following: !!cameraFollowState,
|
|
1877
|
+
activeEffects: cameraEffects.length
|
|
1878
|
+
};
|
|
1879
|
+
};
|
|
1880
|
+
|
|
759
1881
|
function attachListeners() {
|
|
760
1882
|
if (runtime.listenersAttached) return;
|
|
761
1883
|
runtime.listenersAttached = true;
|
|
@@ -782,12 +1904,44 @@ const WEB_LOADER_SOURCE = `
|
|
|
782
1904
|
}
|
|
783
1905
|
};
|
|
784
1906
|
|
|
1907
|
+
runtime.mousemoveListener = function (event) {
|
|
1908
|
+
syncMousePosition(event);
|
|
1909
|
+
};
|
|
1910
|
+
|
|
1911
|
+
runtime.mousedownListener = function (event) {
|
|
1912
|
+
syncMousePosition(event);
|
|
1913
|
+
const button = normalizeMouseButton(event && event.button);
|
|
1914
|
+
if (!inputState.mouseDown.has(button)) {
|
|
1915
|
+
inputState.pendingMousePressed.add(button);
|
|
1916
|
+
}
|
|
1917
|
+
inputState.mouseDown.add(button);
|
|
1918
|
+
};
|
|
1919
|
+
|
|
1920
|
+
runtime.mouseupListener = function (event) {
|
|
1921
|
+
syncMousePosition(event);
|
|
1922
|
+
const button = normalizeMouseButton(event && event.button);
|
|
1923
|
+
inputState.mouseDown.delete(button);
|
|
1924
|
+
inputState.pendingMouseReleased.add(button);
|
|
1925
|
+
};
|
|
1926
|
+
|
|
1927
|
+
runtime.wheelListener = function (event) {
|
|
1928
|
+
if (event && Number.isFinite(Number(event.deltaY))) {
|
|
1929
|
+
auraRef.input.mouse.scroll += Number(event.deltaY);
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
|
|
1933
|
+
runtime.focusListener = function () {
|
|
1934
|
+
clearMouseDeltaState();
|
|
1935
|
+
if (typeof auraRef.onFocus === 'function') {
|
|
1936
|
+
auraRef.onFocus();
|
|
1937
|
+
}
|
|
1938
|
+
};
|
|
1939
|
+
|
|
785
1940
|
runtime.blurListener = function () {
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
inputState.frameReleased.clear();
|
|
1941
|
+
clearHeldInputState();
|
|
1942
|
+
if (typeof auraRef.onBlur === 'function') {
|
|
1943
|
+
auraRef.onBlur();
|
|
1944
|
+
}
|
|
791
1945
|
};
|
|
792
1946
|
|
|
793
1947
|
runtime.resizeListener = function () {
|
|
@@ -797,6 +1951,11 @@ const WEB_LOADER_SOURCE = `
|
|
|
797
1951
|
if (typeof globalRef.addEventListener === 'function') {
|
|
798
1952
|
globalRef.addEventListener('keydown', runtime.keydownListener);
|
|
799
1953
|
globalRef.addEventListener('keyup', runtime.keyupListener);
|
|
1954
|
+
globalRef.addEventListener('focus', runtime.focusListener);
|
|
1955
|
+
globalRef.addEventListener('mousemove', runtime.mousemoveListener);
|
|
1956
|
+
globalRef.addEventListener('mousedown', runtime.mousedownListener);
|
|
1957
|
+
globalRef.addEventListener('mouseup', runtime.mouseupListener);
|
|
1958
|
+
globalRef.addEventListener('wheel', runtime.wheelListener);
|
|
800
1959
|
globalRef.addEventListener('blur', runtime.blurListener);
|
|
801
1960
|
globalRef.addEventListener('resize', runtime.resizeListener);
|
|
802
1961
|
}
|
|
@@ -808,6 +1967,11 @@ const WEB_LOADER_SOURCE = `
|
|
|
808
1967
|
if (typeof globalRef.removeEventListener === 'function') {
|
|
809
1968
|
globalRef.removeEventListener('keydown', runtime.keydownListener);
|
|
810
1969
|
globalRef.removeEventListener('keyup', runtime.keyupListener);
|
|
1970
|
+
globalRef.removeEventListener('focus', runtime.focusListener);
|
|
1971
|
+
globalRef.removeEventListener('mousemove', runtime.mousemoveListener);
|
|
1972
|
+
globalRef.removeEventListener('mousedown', runtime.mousedownListener);
|
|
1973
|
+
globalRef.removeEventListener('mouseup', runtime.mouseupListener);
|
|
1974
|
+
globalRef.removeEventListener('wheel', runtime.wheelListener);
|
|
811
1975
|
globalRef.removeEventListener('blur', runtime.blurListener);
|
|
812
1976
|
globalRef.removeEventListener('resize', runtime.resizeListener);
|
|
813
1977
|
}
|
|
@@ -824,6 +1988,9 @@ const WEB_LOADER_SOURCE = `
|
|
|
824
1988
|
auraRef.rgba = function (r, g, b, a) {
|
|
825
1989
|
return createUnitColor(r, g, b, a == null ? 1 : a);
|
|
826
1990
|
};
|
|
1991
|
+
auraRef.rgb = function (r, g, b) {
|
|
1992
|
+
return createUnitColor(r, g, b, 1);
|
|
1993
|
+
};
|
|
827
1994
|
auraRef.color = auraRef.rgba;
|
|
828
1995
|
auraRef.Color = auraRef.Color && typeof auraRef.Color === 'object'
|
|
829
1996
|
? auraRef.Color
|
|
@@ -844,6 +2011,19 @@ const WEB_LOADER_SOURCE = `
|
|
|
844
2011
|
transparent: createByteColor(0, 0, 0, 0)
|
|
845
2012
|
};
|
|
846
2013
|
|
|
2014
|
+
auraRef.math = auraRef.math && typeof auraRef.math === 'object' ? auraRef.math : {};
|
|
2015
|
+
auraRef.math.clamp = typeof auraRef.math.clamp === 'function'
|
|
2016
|
+
? auraRef.math.clamp
|
|
2017
|
+
: function (value, min, max) {
|
|
2018
|
+
const numeric = Number(value);
|
|
2019
|
+
const minValue = Number(min);
|
|
2020
|
+
const maxValue = Number(max);
|
|
2021
|
+
if (!Number.isFinite(numeric) || !Number.isFinite(minValue) || !Number.isFinite(maxValue)) {
|
|
2022
|
+
return Number.isFinite(numeric) ? numeric : 0;
|
|
2023
|
+
}
|
|
2024
|
+
return Math.min(maxValue, Math.max(minValue, numeric));
|
|
2025
|
+
};
|
|
2026
|
+
|
|
847
2027
|
auraRef.window = auraRef.window && typeof auraRef.window === 'object' ? auraRef.window : {};
|
|
848
2028
|
auraRef.window.width = runtime.width;
|
|
849
2029
|
auraRef.window.height = runtime.height;
|
|
@@ -864,6 +2044,26 @@ const WEB_LOADER_SOURCE = `
|
|
|
864
2044
|
auraRef.window.setFullscreen = function () {
|
|
865
2045
|
return false;
|
|
866
2046
|
};
|
|
2047
|
+
auraRef.window.setCursorVisible = function (visible) {
|
|
2048
|
+
runtime.cursorVisible = !!visible;
|
|
2049
|
+
applyCursorAppearance();
|
|
2050
|
+
return true;
|
|
2051
|
+
};
|
|
2052
|
+
auraRef.window.setCursorLocked = function (locked) {
|
|
2053
|
+
runtime.cursorLocked = !!locked;
|
|
2054
|
+
clearMouseDeltaState();
|
|
2055
|
+
applyCursorAppearance();
|
|
2056
|
+
if (runtime.canvas && typeof runtime.canvas.requestPointerLock === 'function' && runtime.cursorLocked) {
|
|
2057
|
+
runtime.canvas.requestPointerLock();
|
|
2058
|
+
} else if (
|
|
2059
|
+
!runtime.cursorLocked &&
|
|
2060
|
+
globalRef.document &&
|
|
2061
|
+
typeof globalRef.document.exitPointerLock === 'function'
|
|
2062
|
+
) {
|
|
2063
|
+
globalRef.document.exitPointerLock();
|
|
2064
|
+
}
|
|
2065
|
+
return true;
|
|
2066
|
+
};
|
|
867
2067
|
auraRef.window.getSize = function () {
|
|
868
2068
|
return { width: runtime.width, height: runtime.height };
|
|
869
2069
|
};
|
|
@@ -884,6 +2084,8 @@ const WEB_LOADER_SOURCE = `
|
|
|
884
2084
|
auraRef.collide = auraRef.collide && typeof auraRef.collide === 'object' ? auraRef.collide : auraRef.collision;
|
|
885
2085
|
auraRef.collide.rectRect = auraRef.collision.rectRect;
|
|
886
2086
|
|
|
2087
|
+
auraRef.camera = camera;
|
|
2088
|
+
|
|
887
2089
|
auraRef.input = auraRef.input && typeof auraRef.input === 'object' ? auraRef.input : {};
|
|
888
2090
|
auraRef.input.isDown = function (name) {
|
|
889
2091
|
const key = normalizeKeyName(name);
|
|
@@ -906,39 +2108,390 @@ const WEB_LOADER_SOURCE = `
|
|
|
906
2108
|
auraRef.input.isKeyReleased = function (name) {
|
|
907
2109
|
return auraRef.input.isReleased(name);
|
|
908
2110
|
};
|
|
2111
|
+
auraRef.input.isGamepadConnected = typeof auraRef.input.isGamepadConnected === 'function'
|
|
2112
|
+
? auraRef.input.isGamepadConnected
|
|
2113
|
+
: function () { return false; };
|
|
909
2114
|
auraRef.input.mouse = auraRef.input.mouse && typeof auraRef.input.mouse === 'object' ? auraRef.input.mouse : {};
|
|
910
2115
|
auraRef.input.mouse.x = Number(auraRef.input.mouse.x) || 0;
|
|
911
2116
|
auraRef.input.mouse.y = Number(auraRef.input.mouse.y) || 0;
|
|
912
2117
|
auraRef.input.mouse.scroll = Number(auraRef.input.mouse.scroll) || 0;
|
|
913
|
-
auraRef.input.mouse.isDown = function () {
|
|
914
|
-
|
|
915
|
-
|
|
2118
|
+
auraRef.input.mouse.isDown = function (button) {
|
|
2119
|
+
return inputState.mouseDown.has(normalizeMouseButton(button));
|
|
2120
|
+
};
|
|
2121
|
+
auraRef.input.mouse.isPressed = function (button) {
|
|
2122
|
+
return inputState.frameMousePressed.has(normalizeMouseButton(button));
|
|
2123
|
+
};
|
|
2124
|
+
auraRef.input.mouse.isReleased = function (button) {
|
|
2125
|
+
return inputState.frameMouseReleased.has(normalizeMouseButton(button));
|
|
2126
|
+
};
|
|
2127
|
+
auraRef.input.isMouseDown = function (button) {
|
|
2128
|
+
return auraRef.input.mouse.isDown(button);
|
|
2129
|
+
};
|
|
2130
|
+
auraRef.input.isMousePressed = function (button) {
|
|
2131
|
+
return auraRef.input.mouse.isPressed(button);
|
|
2132
|
+
};
|
|
2133
|
+
auraRef.input.isMouseReleased = function (button) {
|
|
2134
|
+
return auraRef.input.mouse.isReleased(button);
|
|
2135
|
+
};
|
|
916
2136
|
auraRef.input.getMousePosition = function () {
|
|
917
2137
|
return { x: auraRef.input.mouse.x, y: auraRef.input.mouse.y };
|
|
918
2138
|
};
|
|
2139
|
+
auraRef.input.getMouseDelta = function () {
|
|
2140
|
+
return { x: inputState.frameMouseDeltaX, y: inputState.frameMouseDeltaY };
|
|
2141
|
+
};
|
|
2142
|
+
|
|
2143
|
+
auraRef.state = auraRef.state && typeof auraRef.state === 'object' ? auraRef.state : {};
|
|
2144
|
+
auraRef.state.export = typeof auraRef.state.export === 'function'
|
|
2145
|
+
? auraRef.state.export
|
|
2146
|
+
: function () {
|
|
2147
|
+
return createUnsupportedStateResult('export', 'web_state_export_unsupported');
|
|
2148
|
+
};
|
|
2149
|
+
auraRef.state.apply = typeof auraRef.state.apply === 'function'
|
|
2150
|
+
? auraRef.state.apply
|
|
2151
|
+
: function () {
|
|
2152
|
+
return createUnsupportedStateResult('apply', 'web_state_apply_unsupported');
|
|
2153
|
+
};
|
|
2154
|
+
auraRef.state.diff = typeof auraRef.state.diff === 'function'
|
|
2155
|
+
? auraRef.state.diff
|
|
2156
|
+
: function () {
|
|
2157
|
+
return createUnsupportedStateResult('diff', 'web_state_diff_unsupported');
|
|
2158
|
+
};
|
|
2159
|
+
auraRef.state.patch = typeof auraRef.state.patch === 'function'
|
|
2160
|
+
? auraRef.state.patch
|
|
2161
|
+
: function () {
|
|
2162
|
+
return createUnsupportedStateResult('patch', 'web_state_patch_unsupported');
|
|
2163
|
+
};
|
|
2164
|
+
auraRef.state.exportState = typeof auraRef.state.exportState === 'function'
|
|
2165
|
+
? auraRef.state.exportState
|
|
2166
|
+
: function (options) {
|
|
2167
|
+
return auraRef.state.export(options);
|
|
2168
|
+
};
|
|
2169
|
+
auraRef.state.applyState = typeof auraRef.state.applyState === 'function'
|
|
2170
|
+
? auraRef.state.applyState
|
|
2171
|
+
: function (payload, options) {
|
|
2172
|
+
return auraRef.state.apply(payload, options);
|
|
2173
|
+
};
|
|
2174
|
+
auraRef.state.diffState = typeof auraRef.state.diffState === 'function'
|
|
2175
|
+
? auraRef.state.diffState
|
|
2176
|
+
: function (beforePayload, afterPayload) {
|
|
2177
|
+
return auraRef.state.diff(beforePayload, afterPayload);
|
|
2178
|
+
};
|
|
2179
|
+
auraRef.state.patchState = typeof auraRef.state.patchState === 'function'
|
|
2180
|
+
? auraRef.state.patchState
|
|
2181
|
+
: function (payload, patchPayload, options) {
|
|
2182
|
+
return auraRef.state.patch(payload, patchPayload, options);
|
|
2183
|
+
};
|
|
2184
|
+
|
|
2185
|
+
auraRef.net = auraRef.net && typeof auraRef.net === 'object' ? auraRef.net : {};
|
|
2186
|
+
auraRef.net.connect = typeof auraRef.net.connect === 'function'
|
|
2187
|
+
? auraRef.net.connect
|
|
2188
|
+
: function () {
|
|
2189
|
+
throw createUnsupportedRuntimeError('net', 'connect', 'web_net_connect_unsupported');
|
|
2190
|
+
};
|
|
2191
|
+
auraRef.net.websocket = typeof auraRef.net.websocket === 'function'
|
|
2192
|
+
? auraRef.net.websocket
|
|
2193
|
+
: function () {
|
|
2194
|
+
throw createUnsupportedRuntimeError('net', 'websocket', 'web_net_websocket_unsupported');
|
|
2195
|
+
};
|
|
2196
|
+
auraRef.net.fetch = typeof auraRef.net.fetch === 'function'
|
|
2197
|
+
? auraRef.net.fetch
|
|
2198
|
+
: function () {
|
|
2199
|
+
throw createUnsupportedRuntimeError('net', 'fetch', 'web_net_fetch_unsupported');
|
|
2200
|
+
};
|
|
2201
|
+
auraRef.net.get = typeof auraRef.net.get === 'function'
|
|
2202
|
+
? auraRef.net.get
|
|
2203
|
+
: function () {
|
|
2204
|
+
throw createUnsupportedRuntimeError('net', 'get', 'web_net_get_unsupported');
|
|
2205
|
+
};
|
|
2206
|
+
auraRef.net.post = typeof auraRef.net.post === 'function'
|
|
2207
|
+
? auraRef.net.post
|
|
2208
|
+
: function () {
|
|
2209
|
+
throw createUnsupportedRuntimeError('net', 'post', 'web_net_post_unsupported');
|
|
2210
|
+
};
|
|
2211
|
+
|
|
2212
|
+
auraRef.storage = auraRef.storage && typeof auraRef.storage === 'object' ? auraRef.storage : {};
|
|
2213
|
+
auraRef.storage.save = typeof auraRef.storage.save === 'function'
|
|
2214
|
+
? auraRef.storage.save
|
|
2215
|
+
: function (key, value) { return writeStorage(key, value); };
|
|
2216
|
+
auraRef.storage.load = typeof auraRef.storage.load === 'function'
|
|
2217
|
+
? auraRef.storage.load
|
|
2218
|
+
: function (key) { return readStorage(key); };
|
|
2219
|
+
auraRef.storage.delete = typeof auraRef.storage.delete === 'function'
|
|
2220
|
+
? auraRef.storage.delete
|
|
2221
|
+
: function (key) { return deleteStorage(key); };
|
|
2222
|
+
auraRef.storage.keys = typeof auraRef.storage.keys === 'function'
|
|
2223
|
+
? auraRef.storage.keys
|
|
2224
|
+
: function () {
|
|
2225
|
+
const prefix = 'aurajs:';
|
|
2226
|
+
const backend = resolveStorageBackend();
|
|
2227
|
+
const keys = [];
|
|
2228
|
+
if (backend && Number.isInteger(backend.length) && typeof backend.key === 'function') {
|
|
2229
|
+
for (let index = 0; index < backend.length; index += 1) {
|
|
2230
|
+
const nextKey = backend.key(index);
|
|
2231
|
+
if (typeof nextKey === 'string' && nextKey.startsWith(prefix)) {
|
|
2232
|
+
keys.push(nextKey.slice(prefix.length));
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
keys.sort(function (a, b) { return a.localeCompare(b); });
|
|
2236
|
+
return keys;
|
|
2237
|
+
}
|
|
2238
|
+
for (const key of assetState.storageFallback.keys()) {
|
|
2239
|
+
if (key.startsWith(prefix)) {
|
|
2240
|
+
keys.push(key.slice(prefix.length));
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
keys.sort(function (a, b) { return a.localeCompare(b); });
|
|
2244
|
+
return keys;
|
|
2245
|
+
};
|
|
2246
|
+
auraRef.storage.set = typeof auraRef.storage.set === 'function'
|
|
2247
|
+
? auraRef.storage.set
|
|
2248
|
+
: function (key, value) { return writeStorage(key, value); };
|
|
2249
|
+
auraRef.storage.get = typeof auraRef.storage.get === 'function'
|
|
2250
|
+
? auraRef.storage.get
|
|
2251
|
+
: function (key, fallback) {
|
|
2252
|
+
const value = readStorage(key);
|
|
2253
|
+
return value == null ? fallback : value;
|
|
2254
|
+
};
|
|
2255
|
+
|
|
2256
|
+
auraRef.audio = auraRef.audio && typeof auraRef.audio === 'object' ? auraRef.audio : {};
|
|
2257
|
+
if (auraRef.audio.supported !== true) {
|
|
2258
|
+
auraRef.audio.supported = false;
|
|
2259
|
+
}
|
|
2260
|
+
if (typeof auraRef.audio.reasonCode !== 'string') {
|
|
2261
|
+
auraRef.audio.reasonCode = 'web_audio_playback_unsupported';
|
|
2262
|
+
}
|
|
2263
|
+
if (typeof auraRef.audio.runtime !== 'string') {
|
|
2264
|
+
auraRef.audio.runtime = 'web';
|
|
2265
|
+
}
|
|
2266
|
+
auraRef.audio.play = typeof auraRef.audio.play === 'function'
|
|
2267
|
+
? auraRef.audio.play
|
|
2268
|
+
: function () {
|
|
2269
|
+
throw createUnsupportedRuntimeError('audio', 'play', 'web_audio_play_unsupported', { playbackSupported: false });
|
|
2270
|
+
};
|
|
2271
|
+
auraRef.audio.stop = typeof auraRef.audio.stop === 'function'
|
|
2272
|
+
? auraRef.audio.stop
|
|
2273
|
+
: function () {
|
|
2274
|
+
throw createUnsupportedRuntimeError('audio', 'stop', 'web_audio_stop_unsupported', { playbackSupported: false });
|
|
2275
|
+
};
|
|
2276
|
+
auraRef.audio.pause = typeof auraRef.audio.pause === 'function'
|
|
2277
|
+
? auraRef.audio.pause
|
|
2278
|
+
: function () {
|
|
2279
|
+
throw createUnsupportedRuntimeError('audio', 'pause', 'web_audio_pause_unsupported', { playbackSupported: false });
|
|
2280
|
+
};
|
|
2281
|
+
auraRef.audio.resume = typeof auraRef.audio.resume === 'function'
|
|
2282
|
+
? auraRef.audio.resume
|
|
2283
|
+
: function () {
|
|
2284
|
+
throw createUnsupportedRuntimeError('audio', 'resume', 'web_audio_resume_unsupported', { playbackSupported: false });
|
|
2285
|
+
};
|
|
2286
|
+
auraRef.audio.setVolume = typeof auraRef.audio.setVolume === 'function'
|
|
2287
|
+
? auraRef.audio.setVolume
|
|
2288
|
+
: function () {
|
|
2289
|
+
throw createUnsupportedRuntimeError('audio', 'setVolume', 'web_audio_set_volume_unsupported', { playbackSupported: false });
|
|
2290
|
+
};
|
|
2291
|
+
auraRef.audio.setMasterVolume = typeof auraRef.audio.setMasterVolume === 'function'
|
|
2292
|
+
? auraRef.audio.setMasterVolume
|
|
2293
|
+
: function () {
|
|
2294
|
+
throw createUnsupportedRuntimeError('audio', 'setMasterVolume', 'web_audio_set_master_volume_unsupported', { playbackSupported: false });
|
|
2295
|
+
};
|
|
2296
|
+
auraRef.audio.stopAll = typeof auraRef.audio.stopAll === 'function'
|
|
2297
|
+
? auraRef.audio.stopAll
|
|
2298
|
+
: function () {
|
|
2299
|
+
throw createUnsupportedRuntimeError('audio', 'stopAll', 'web_audio_stop_all_unsupported', { playbackSupported: false });
|
|
2300
|
+
};
|
|
2301
|
+
auraRef.audio.setBusVolume = typeof auraRef.audio.setBusVolume === 'function'
|
|
2302
|
+
? auraRef.audio.setBusVolume
|
|
2303
|
+
: function () {
|
|
2304
|
+
throw createUnsupportedRuntimeError('audio', 'setBusVolume', 'web_audio_set_bus_volume_unsupported', { playbackSupported: false });
|
|
2305
|
+
};
|
|
2306
|
+
auraRef.audio.assignBus = typeof auraRef.audio.assignBus === 'function'
|
|
2307
|
+
? auraRef.audio.assignBus
|
|
2308
|
+
: function () {
|
|
2309
|
+
throw createUnsupportedRuntimeError('audio', 'assignBus', 'web_audio_assign_bus_unsupported', { playbackSupported: false });
|
|
2310
|
+
};
|
|
2311
|
+
auraRef.audio.fadeTrack = typeof auraRef.audio.fadeTrack === 'function'
|
|
2312
|
+
? auraRef.audio.fadeTrack
|
|
2313
|
+
: function () {
|
|
2314
|
+
throw createUnsupportedRuntimeError('audio', 'fadeTrack', 'web_audio_fade_track_unsupported', { playbackSupported: false });
|
|
2315
|
+
};
|
|
2316
|
+
auraRef.audio.fadeBus = typeof auraRef.audio.fadeBus === 'function'
|
|
2317
|
+
? auraRef.audio.fadeBus
|
|
2318
|
+
: function () {
|
|
2319
|
+
throw createUnsupportedRuntimeError('audio', 'fadeBus', 'web_audio_fade_bus_unsupported', { playbackSupported: false });
|
|
2320
|
+
};
|
|
2321
|
+
auraRef.audio.crossfade = typeof auraRef.audio.crossfade === 'function'
|
|
2322
|
+
? auraRef.audio.crossfade
|
|
2323
|
+
: function () {
|
|
2324
|
+
throw createUnsupportedRuntimeError('audio', 'crossfade', 'web_audio_crossfade_unsupported', { playbackSupported: false });
|
|
2325
|
+
};
|
|
2326
|
+
auraRef.audio.update = typeof auraRef.audio.update === 'function'
|
|
2327
|
+
? auraRef.audio.update
|
|
2328
|
+
: function () {
|
|
2329
|
+
throw createUnsupportedRuntimeError('audio', 'update', 'web_audio_update_unsupported', { playbackSupported: false });
|
|
2330
|
+
};
|
|
2331
|
+
auraRef.audio.clearEnvelopes = typeof auraRef.audio.clearEnvelopes === 'function'
|
|
2332
|
+
? auraRef.audio.clearEnvelopes
|
|
2333
|
+
: function () {
|
|
2334
|
+
throw createUnsupportedRuntimeError('audio', 'clearEnvelopes', 'web_audio_clear_envelopes_unsupported', { playbackSupported: false });
|
|
2335
|
+
};
|
|
2336
|
+
auraRef.audio.getMixerState = typeof auraRef.audio.getMixerState === 'function'
|
|
2337
|
+
? auraRef.audio.getMixerState
|
|
2338
|
+
: function () {
|
|
2339
|
+
throw createUnsupportedRuntimeError('audio', 'getMixerState', 'web_audio_get_mixer_state_unsupported', { playbackSupported: false });
|
|
2340
|
+
};
|
|
2341
|
+
auraRef.audio.play3d = typeof auraRef.audio.play3d === 'function'
|
|
2342
|
+
? auraRef.audio.play3d
|
|
2343
|
+
: function () {
|
|
2344
|
+
throw createUnsupportedRuntimeError('audio', 'play3d', 'web_audio_play3d_unsupported', { playbackSupported: false });
|
|
2345
|
+
};
|
|
2346
|
+
auraRef.audio.setListenerTransform = typeof auraRef.audio.setListenerTransform === 'function'
|
|
2347
|
+
? auraRef.audio.setListenerTransform
|
|
2348
|
+
: function () {
|
|
2349
|
+
throw createUnsupportedRuntimeError('audio', 'setListenerTransform', 'web_audio_set_listener_transform_unsupported', { playbackSupported: false });
|
|
2350
|
+
};
|
|
2351
|
+
auraRef.audio.attachListener = typeof auraRef.audio.attachListener === 'function'
|
|
2352
|
+
? auraRef.audio.attachListener
|
|
2353
|
+
: function () {
|
|
2354
|
+
throw createUnsupportedRuntimeError('audio', 'attachListener', 'web_audio_attach_listener_unsupported', { playbackSupported: false });
|
|
2355
|
+
};
|
|
2356
|
+
auraRef.audio.detachListener = typeof auraRef.audio.detachListener === 'function'
|
|
2357
|
+
? auraRef.audio.detachListener
|
|
2358
|
+
: function () {
|
|
2359
|
+
throw createUnsupportedRuntimeError('audio', 'detachListener', 'web_audio_detach_listener_unsupported', { playbackSupported: false });
|
|
2360
|
+
};
|
|
2361
|
+
auraRef.audio.setEmitterTransform = typeof auraRef.audio.setEmitterTransform === 'function'
|
|
2362
|
+
? auraRef.audio.setEmitterTransform
|
|
2363
|
+
: function () {
|
|
2364
|
+
throw createUnsupportedRuntimeError('audio', 'setEmitterTransform', 'web_audio_set_emitter_transform_unsupported', { playbackSupported: false });
|
|
2365
|
+
};
|
|
2366
|
+
auraRef.audio.attachEmitter = typeof auraRef.audio.attachEmitter === 'function'
|
|
2367
|
+
? auraRef.audio.attachEmitter
|
|
2368
|
+
: function () {
|
|
2369
|
+
throw createUnsupportedRuntimeError('audio', 'attachEmitter', 'web_audio_attach_emitter_unsupported', { playbackSupported: false });
|
|
2370
|
+
};
|
|
2371
|
+
auraRef.audio.detachEmitter = typeof auraRef.audio.detachEmitter === 'function'
|
|
2372
|
+
? auraRef.audio.detachEmitter
|
|
2373
|
+
: function () {
|
|
2374
|
+
throw createUnsupportedRuntimeError('audio', 'detachEmitter', 'web_audio_detach_emitter_unsupported', { playbackSupported: false });
|
|
2375
|
+
};
|
|
2376
|
+
auraRef.audio.updateSpatial = typeof auraRef.audio.updateSpatial === 'function'
|
|
2377
|
+
? auraRef.audio.updateSpatial
|
|
2378
|
+
: function () {
|
|
2379
|
+
throw createUnsupportedRuntimeError('audio', 'updateSpatial', 'web_audio_update_spatial_unsupported', { playbackSupported: false });
|
|
2380
|
+
};
|
|
2381
|
+
auraRef.audio.getSpatialState = typeof auraRef.audio.getSpatialState === 'function'
|
|
2382
|
+
? auraRef.audio.getSpatialState
|
|
2383
|
+
: function () {
|
|
2384
|
+
throw createUnsupportedRuntimeError('audio', 'getSpatialState', 'web_audio_get_spatial_state_unsupported', { playbackSupported: false });
|
|
2385
|
+
};
|
|
919
2386
|
|
|
920
2387
|
auraRef.assets = auraRef.assets && typeof auraRef.assets === 'object' ? auraRef.assets : {};
|
|
921
2388
|
auraRef.assets.load = typeof auraRef.assets.load === 'function'
|
|
922
2389
|
? auraRef.assets.load
|
|
923
|
-
: async function () {
|
|
2390
|
+
: async function (source) {
|
|
2391
|
+
return await loadAssetRecord(source);
|
|
2392
|
+
};
|
|
924
2393
|
auraRef.assets.exists = typeof auraRef.assets.exists === 'function'
|
|
925
2394
|
? auraRef.assets.exists
|
|
926
|
-
: function () {
|
|
2395
|
+
: function (name) {
|
|
2396
|
+
return !!resolveAssetEntry(name);
|
|
2397
|
+
};
|
|
927
2398
|
auraRef.assets.image = typeof auraRef.assets.image === 'function'
|
|
928
2399
|
? auraRef.assets.image
|
|
929
|
-
: function (name) {
|
|
2400
|
+
: function (name) {
|
|
2401
|
+
const sourcePath = resolveAssetSourcePath(name);
|
|
2402
|
+
const loaded = resolveLoadedAsset(sourcePath);
|
|
2403
|
+
if (loaded) return loaded;
|
|
2404
|
+
const entry = resolveAssetEntry(sourcePath);
|
|
2405
|
+
return rememberLoadedAsset(sourcePath, {
|
|
2406
|
+
kind: 'image',
|
|
2407
|
+
path: sourcePath,
|
|
2408
|
+
sourcePath: sourcePath,
|
|
2409
|
+
resolvedPath: entry && typeof entry.path === 'string' ? normalizePath(entry.path) : sourcePath,
|
|
2410
|
+
mediaType: entry && typeof entry.mediaType === 'string' ? entry.mediaType : 'image/png',
|
|
2411
|
+
image: null,
|
|
2412
|
+
width: 0,
|
|
2413
|
+
height: 0
|
|
2414
|
+
});
|
|
2415
|
+
};
|
|
930
2416
|
auraRef.assets.sound = typeof auraRef.assets.sound === 'function'
|
|
931
2417
|
? auraRef.assets.sound
|
|
932
|
-
: function (name) {
|
|
2418
|
+
: function (name) {
|
|
2419
|
+
const sourcePath = resolveAssetSourcePath(name);
|
|
2420
|
+
const loaded = resolveLoadedAsset(sourcePath);
|
|
2421
|
+
if (loaded) return loaded;
|
|
2422
|
+
const entry = resolveAssetEntry(sourcePath);
|
|
2423
|
+
return createBrowserSoundHandle(sourcePath, entry, null);
|
|
2424
|
+
};
|
|
933
2425
|
auraRef.assets.text = typeof auraRef.assets.text === 'function'
|
|
934
2426
|
? auraRef.assets.text
|
|
935
|
-
: function () {
|
|
2427
|
+
: function (name) {
|
|
2428
|
+
const loaded = resolveLoadedAsset(name);
|
|
2429
|
+
return loaded && typeof loaded.text === 'string' ? loaded.text : '';
|
|
2430
|
+
};
|
|
936
2431
|
auraRef.assets.json = typeof auraRef.assets.json === 'function'
|
|
937
2432
|
? auraRef.assets.json
|
|
938
|
-
: function () {
|
|
2433
|
+
: function (name) {
|
|
2434
|
+
const loaded = resolveLoadedAsset(name);
|
|
2435
|
+
return loaded && loaded.json && typeof loaded.json === 'object' ? loaded.json : {};
|
|
2436
|
+
};
|
|
939
2437
|
auraRef.assets.bytes = typeof auraRef.assets.bytes === 'function'
|
|
940
2438
|
? auraRef.assets.bytes
|
|
941
|
-
: function () {
|
|
2439
|
+
: function (name) {
|
|
2440
|
+
const loaded = resolveLoadedAsset(name);
|
|
2441
|
+
return loaded && loaded.bytes instanceof Uint8Array ? loaded.bytes : new Uint8Array();
|
|
2442
|
+
};
|
|
2443
|
+
auraRef.assets.loadText = typeof auraRef.assets.loadText === 'function'
|
|
2444
|
+
? auraRef.assets.loadText
|
|
2445
|
+
: async function (name) {
|
|
2446
|
+
const loaded = await loadAssetRecord(name);
|
|
2447
|
+
return loaded && typeof loaded.text === 'string' ? loaded.text : '';
|
|
2448
|
+
};
|
|
2449
|
+
auraRef.assets.loadJson = typeof auraRef.assets.loadJson === 'function'
|
|
2450
|
+
? auraRef.assets.loadJson
|
|
2451
|
+
: async function (name) {
|
|
2452
|
+
const loaded = await loadAssetRecord(name);
|
|
2453
|
+
return loaded && loaded.json && typeof loaded.json === 'object' ? loaded.json : null;
|
|
2454
|
+
};
|
|
2455
|
+
|
|
2456
|
+
function drawResolvedImage(source, x, y, options, useSpriteFrame) {
|
|
2457
|
+
const ctx = ensureWorldTransform();
|
|
2458
|
+
if (!ctx || typeof ctx.drawImage !== 'function') return false;
|
|
2459
|
+
const handle = source && typeof source === 'object' && source.image
|
|
2460
|
+
? source
|
|
2461
|
+
: auraRef.assets.image(source);
|
|
2462
|
+
if (!handle || !handle.image) return false;
|
|
2463
|
+
const opts = options && typeof options === 'object' ? { ...options } : {};
|
|
2464
|
+
const width = normalizePositiveNumber(opts.width, handle.width || handle.image.naturalWidth || handle.image.width || 1);
|
|
2465
|
+
const height = normalizePositiveNumber(opts.height, handle.height || handle.image.naturalHeight || handle.image.height || 1);
|
|
2466
|
+
const alpha = Number.isFinite(Number(opts.alpha)) ? Math.max(0, Math.min(1, Number(opts.alpha))) : 1;
|
|
2467
|
+
const frameX = useSpriteFrame ? Math.max(0, Number(opts.frameX) || 0) : 0;
|
|
2468
|
+
const frameY = useSpriteFrame ? Math.max(0, Number(opts.frameY) || 0) : 0;
|
|
2469
|
+
const frameW = useSpriteFrame
|
|
2470
|
+
? normalizePositiveNumber(opts.frameW, handle.image.naturalWidth || handle.image.width || width)
|
|
2471
|
+
: (handle.image.naturalWidth || handle.image.width || width);
|
|
2472
|
+
const frameH = useSpriteFrame
|
|
2473
|
+
? normalizePositiveNumber(opts.frameH, handle.image.naturalHeight || handle.image.height || height)
|
|
2474
|
+
: (handle.image.naturalHeight || handle.image.height || height);
|
|
2475
|
+
const drawX = Number(x) || 0;
|
|
2476
|
+
const drawY = Number(y) || 0;
|
|
2477
|
+
const flipX = opts.flipX === true;
|
|
2478
|
+
const flipY = opts.flipY === true;
|
|
2479
|
+
if (typeof ctx.save === 'function') ctx.save();
|
|
2480
|
+
ctx.globalAlpha = alpha;
|
|
2481
|
+
if (flipX || flipY) {
|
|
2482
|
+
if (typeof ctx.translate === 'function') {
|
|
2483
|
+
ctx.translate(drawX + (flipX ? width : 0), drawY + (flipY ? height : 0));
|
|
2484
|
+
}
|
|
2485
|
+
if (typeof ctx.scale === 'function') {
|
|
2486
|
+
ctx.scale(flipX ? -1 : 1, flipY ? -1 : 1);
|
|
2487
|
+
}
|
|
2488
|
+
ctx.drawImage(handle.image, frameX, frameY, frameW, frameH, 0, 0, width, height);
|
|
2489
|
+
} else {
|
|
2490
|
+
ctx.drawImage(handle.image, frameX, frameY, frameW, frameH, drawX, drawY, width, height);
|
|
2491
|
+
}
|
|
2492
|
+
if (typeof ctx.restore === 'function') ctx.restore();
|
|
2493
|
+
return true;
|
|
2494
|
+
}
|
|
942
2495
|
|
|
943
2496
|
auraRef.draw2d = auraRef.draw2d && typeof auraRef.draw2d === 'object' ? auraRef.draw2d : {};
|
|
944
2497
|
auraRef.draw2d.clear = function (colorOrR, g, b, a) {
|
|
@@ -951,9 +2504,10 @@ const WEB_LOADER_SOURCE = `
|
|
|
951
2504
|
ctx.clearRect(0, 0, runtime.width, runtime.height);
|
|
952
2505
|
ctx.fillStyle = colorToCss(fillColor, createUnitColor(0, 0, 0, 1));
|
|
953
2506
|
ctx.fillRect(0, 0, runtime.width, runtime.height);
|
|
2507
|
+
applyWorldTransform();
|
|
954
2508
|
};
|
|
955
2509
|
auraRef.draw2d.rect = function (x, y, w, h, color) {
|
|
956
|
-
const ctx =
|
|
2510
|
+
const ctx = ensureWorldTransform();
|
|
957
2511
|
if (!ctx) return;
|
|
958
2512
|
ctx.strokeStyle = colorToCss(color, defaultColor);
|
|
959
2513
|
ctx.lineWidth = 1;
|
|
@@ -961,13 +2515,13 @@ const WEB_LOADER_SOURCE = `
|
|
|
961
2515
|
};
|
|
962
2516
|
auraRef.draw2d.rectOutline = auraRef.draw2d.rect;
|
|
963
2517
|
auraRef.draw2d.rectFill = function (x, y, w, h, color) {
|
|
964
|
-
const ctx =
|
|
2518
|
+
const ctx = ensureWorldTransform();
|
|
965
2519
|
if (!ctx) return;
|
|
966
2520
|
ctx.fillStyle = colorToCss(color, defaultColor);
|
|
967
2521
|
ctx.fillRect(Number(x) || 0, Number(y) || 0, Number(w) || 0, Number(h) || 0);
|
|
968
2522
|
};
|
|
969
2523
|
auraRef.draw2d.circle = function (x, y, radius, color) {
|
|
970
|
-
const ctx =
|
|
2524
|
+
const ctx = ensureWorldTransform();
|
|
971
2525
|
if (!ctx) return;
|
|
972
2526
|
ctx.beginPath();
|
|
973
2527
|
ctx.arc(Number(x) || 0, Number(y) || 0, Math.max(0, Number(radius) || 0), 0, Math.PI * 2);
|
|
@@ -976,7 +2530,7 @@ const WEB_LOADER_SOURCE = `
|
|
|
976
2530
|
ctx.stroke();
|
|
977
2531
|
};
|
|
978
2532
|
auraRef.draw2d.circleFill = function (x, y, radius, color) {
|
|
979
|
-
const ctx =
|
|
2533
|
+
const ctx = ensureWorldTransform();
|
|
980
2534
|
if (!ctx) return;
|
|
981
2535
|
ctx.beginPath();
|
|
982
2536
|
ctx.arc(Number(x) || 0, Number(y) || 0, Math.max(0, Number(radius) || 0), 0, Math.PI * 2);
|
|
@@ -984,7 +2538,7 @@ const WEB_LOADER_SOURCE = `
|
|
|
984
2538
|
ctx.fill();
|
|
985
2539
|
};
|
|
986
2540
|
auraRef.draw2d.line = function (x1, y1, x2, y2, color, width) {
|
|
987
|
-
const ctx =
|
|
2541
|
+
const ctx = ensureWorldTransform();
|
|
988
2542
|
if (!ctx) return;
|
|
989
2543
|
ctx.beginPath();
|
|
990
2544
|
ctx.moveTo(Number(x1) || 0, Number(y1) || 0);
|
|
@@ -993,17 +2547,20 @@ const WEB_LOADER_SOURCE = `
|
|
|
993
2547
|
ctx.lineWidth = normalizePositiveNumber(width, 1);
|
|
994
2548
|
ctx.stroke();
|
|
995
2549
|
};
|
|
996
|
-
auraRef.draw2d.text = function (text, x, y,
|
|
997
|
-
const
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
2550
|
+
auraRef.draw2d.text = function (text, x, y, sizeOrOptions, colorMaybe) {
|
|
2551
|
+
const options = normalizeTextOptions(sizeOrOptions, colorMaybe);
|
|
2552
|
+
return withScreenSpace(function (ctx) {
|
|
2553
|
+
const config = applyFont(options);
|
|
2554
|
+
const source = options && typeof options === 'object' ? options : {};
|
|
2555
|
+
ctx.fillStyle = colorToCss(source.color, defaultColor);
|
|
2556
|
+
ctx.textAlign = config.align;
|
|
2557
|
+
ctx.textBaseline = 'top';
|
|
2558
|
+
ctx.fillText(String(text == null ? '' : text), Number(x) || 0, Number(y) || 0);
|
|
2559
|
+
return true;
|
|
2560
|
+
});
|
|
1005
2561
|
};
|
|
1006
|
-
auraRef.draw2d.measureText = function (text,
|
|
2562
|
+
auraRef.draw2d.measureText = function (text, sizeOrOptions, colorMaybe) {
|
|
2563
|
+
const options = normalizeTextOptions(sizeOrOptions, colorMaybe);
|
|
1007
2564
|
const source = options && typeof options === 'object' ? options : {};
|
|
1008
2565
|
const size = normalizePositiveNumber(source.size, 16);
|
|
1009
2566
|
const ctx = ensureCanvasContext();
|
|
@@ -1011,21 +2568,27 @@ const WEB_LOADER_SOURCE = `
|
|
|
1011
2568
|
const fallbackWidth = String(text == null ? '' : text).length * size * 0.6;
|
|
1012
2569
|
return { width: Number(fallbackWidth.toFixed(3)), height: size };
|
|
1013
2570
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
2571
|
+
const measuredWidth = withScreenSpace(function () {
|
|
2572
|
+
applyFont(options);
|
|
2573
|
+
const metrics = ctx.measureText(String(text == null ? '' : text));
|
|
2574
|
+
return Number.isFinite(metrics && metrics.width)
|
|
2575
|
+
? metrics.width
|
|
2576
|
+
: String(text == null ? '' : text).length * size * 0.6;
|
|
2577
|
+
});
|
|
2578
|
+
return { width: Number(Number(measuredWidth || 0).toFixed(3)), height: size };
|
|
1020
2579
|
};
|
|
1021
2580
|
auraRef.draw2d.image = typeof auraRef.draw2d.image === 'function'
|
|
1022
2581
|
? auraRef.draw2d.image
|
|
1023
|
-
: function (
|
|
2582
|
+
: function (source, x, y, options) {
|
|
2583
|
+
return drawResolvedImage(source, x, y, options, false);
|
|
2584
|
+
};
|
|
1024
2585
|
auraRef.draw2d.sprite = typeof auraRef.draw2d.sprite === 'function'
|
|
1025
2586
|
? auraRef.draw2d.sprite
|
|
1026
|
-
: function (
|
|
2587
|
+
: function (source, x, y, options) {
|
|
2588
|
+
return drawResolvedImage(source, x, y, options, true);
|
|
2589
|
+
};
|
|
1027
2590
|
auraRef.draw2d.pushTransform = function () {
|
|
1028
|
-
const ctx =
|
|
2591
|
+
const ctx = ensureWorldTransform();
|
|
1029
2592
|
if (!ctx || typeof ctx.save !== 'function') return;
|
|
1030
2593
|
runtime.transformDepth += 1;
|
|
1031
2594
|
ctx.save();
|
|
@@ -1039,20 +2602,20 @@ const WEB_LOADER_SOURCE = `
|
|
|
1039
2602
|
auraRef.draw2d.push = auraRef.draw2d.pushTransform;
|
|
1040
2603
|
auraRef.draw2d.pop = auraRef.draw2d.popTransform;
|
|
1041
2604
|
auraRef.draw2d.translate = function (x, y) {
|
|
1042
|
-
const ctx =
|
|
2605
|
+
const ctx = ensureWorldTransform();
|
|
1043
2606
|
if (!ctx || typeof ctx.translate !== 'function') return;
|
|
1044
2607
|
ctx.translate(Number(x) || 0, Number(y) || 0);
|
|
1045
2608
|
};
|
|
1046
2609
|
auraRef.draw2d.rotate = function (angle) {
|
|
1047
|
-
const ctx =
|
|
2610
|
+
const ctx = ensureWorldTransform();
|
|
1048
2611
|
if (!ctx || typeof ctx.rotate !== 'function') return;
|
|
1049
2612
|
ctx.rotate(Number(angle) || 0);
|
|
1050
2613
|
};
|
|
1051
2614
|
auraRef.draw2d.scale = function (x, y) {
|
|
1052
|
-
const ctx =
|
|
2615
|
+
const ctx = ensureWorldTransform();
|
|
1053
2616
|
if (!ctx || typeof ctx.scale !== 'function') return;
|
|
1054
|
-
const scaleX =
|
|
1055
|
-
const scaleY =
|
|
2617
|
+
const scaleX = Number.isFinite(Number(x)) ? Number(x) : 1;
|
|
2618
|
+
const scaleY = Number.isFinite(Number(y)) ? Number(y) : scaleX;
|
|
1056
2619
|
ctx.scale(scaleX, scaleY);
|
|
1057
2620
|
};
|
|
1058
2621
|
|
|
@@ -1068,6 +2631,9 @@ const WEB_LOADER_SOURCE = `
|
|
|
1068
2631
|
runtime.resizeMode = currentCanvasConfig.resizeMode === 'fixed' ? 'fixed' : 'fit-container';
|
|
1069
2632
|
syncCanvasSize(false);
|
|
1070
2633
|
},
|
|
2634
|
+
setManifest(nextManifest, rootUrl) {
|
|
2635
|
+
indexManifestAssets(nextManifest, rootUrl);
|
|
2636
|
+
},
|
|
1071
2637
|
mount(canvas, mountTarget) {
|
|
1072
2638
|
runtime.canvas = canvas || runtime.canvas;
|
|
1073
2639
|
runtime.mountTarget = mountTarget || runtime.mountTarget;
|
|
@@ -1075,14 +2641,15 @@ const WEB_LOADER_SOURCE = `
|
|
|
1075
2641
|
syncCanvasSize(false);
|
|
1076
2642
|
resetDrawState();
|
|
1077
2643
|
attachListeners();
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
inputState.framePressed.clear();
|
|
1082
|
-
inputState.frameReleased.clear();
|
|
2644
|
+
clearHeldInputState();
|
|
2645
|
+
auraRef.input.mouse.scroll = 0;
|
|
2646
|
+
applyCursorAppearance();
|
|
1083
2647
|
if (runtime.canvas && typeof runtime.canvas.focus === 'function') {
|
|
1084
2648
|
runtime.canvas.focus();
|
|
1085
2649
|
}
|
|
2650
|
+
if (typeof auraRef.onFocus === 'function') {
|
|
2651
|
+
auraRef.onFocus();
|
|
2652
|
+
}
|
|
1086
2653
|
return true;
|
|
1087
2654
|
},
|
|
1088
2655
|
beginFrame() {
|
|
@@ -1090,6 +2657,14 @@ const WEB_LOADER_SOURCE = `
|
|
|
1090
2657
|
inputState.frameReleased = new Set(inputState.pendingReleased);
|
|
1091
2658
|
inputState.pendingPressed.clear();
|
|
1092
2659
|
inputState.pendingReleased.clear();
|
|
2660
|
+
inputState.frameMousePressed = new Set(inputState.pendingMousePressed);
|
|
2661
|
+
inputState.frameMouseReleased = new Set(inputState.pendingMouseReleased);
|
|
2662
|
+
inputState.pendingMousePressed.clear();
|
|
2663
|
+
inputState.pendingMouseReleased.clear();
|
|
2664
|
+
inputState.frameMouseDeltaX = inputState.pendingMouseDeltaX;
|
|
2665
|
+
inputState.frameMouseDeltaY = inputState.pendingMouseDeltaY;
|
|
2666
|
+
inputState.pendingMouseDeltaX = 0;
|
|
2667
|
+
inputState.pendingMouseDeltaY = 0;
|
|
1093
2668
|
resetDrawState();
|
|
1094
2669
|
},
|
|
1095
2670
|
endFrame() {
|
|
@@ -1103,15 +2678,17 @@ const WEB_LOADER_SOURCE = `
|
|
|
1103
2678
|
},
|
|
1104
2679
|
unmount() {
|
|
1105
2680
|
detachListeners();
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
2681
|
+
clearHeldInputState();
|
|
2682
|
+
runtime.cursorLocked = false;
|
|
2683
|
+
if (globalRef.document && typeof globalRef.document.exitPointerLock === 'function') {
|
|
2684
|
+
globalRef.document.exitPointerLock();
|
|
2685
|
+
}
|
|
2686
|
+
applyCursorAppearance();
|
|
1111
2687
|
runtime.mountTarget = null;
|
|
1112
2688
|
runtime.canvas = null;
|
|
1113
2689
|
runtime.context2d = null;
|
|
1114
2690
|
runtime.transformDepth = 0;
|
|
2691
|
+
runtime.worldTransformActive = false;
|
|
1115
2692
|
return true;
|
|
1116
2693
|
}
|
|
1117
2694
|
};
|
|
@@ -1293,6 +2870,7 @@ const WEB_LOADER_SOURCE = `
|
|
|
1293
2870
|
const rootUrl = typeof opts.rootUrl === 'string' && opts.rootUrl.length > 0
|
|
1294
2871
|
? opts.rootUrl.replace(/\\/$/, '')
|
|
1295
2872
|
: '.';
|
|
2873
|
+
cachedRootUrl = rootUrl;
|
|
1296
2874
|
setState('loading', null, null);
|
|
1297
2875
|
|
|
1298
2876
|
cachedManifest = await readJson(rootUrl + '/web-build-manifest.json', 'web_manifest_missing', 'web_manifest_parse_failed');
|
|
@@ -1305,6 +2883,9 @@ const WEB_LOADER_SOURCE = `
|
|
|
1305
2883
|
} else if (typeof auraRuntime.setRuntimeConfig === 'function') {
|
|
1306
2884
|
auraRuntime.setRuntimeConfig(cachedRuntimeConfig);
|
|
1307
2885
|
}
|
|
2886
|
+
if (auraRuntime && typeof auraRuntime.setManifest === 'function') {
|
|
2887
|
+
auraRuntime.setManifest(cachedManifest, cachedRootUrl);
|
|
2888
|
+
}
|
|
1308
2889
|
|
|
1309
2890
|
const bundleEntry = normalizePath(cachedManifest.entrypoints.bundle);
|
|
1310
2891
|
if (bundleEntry.length === 0) {
|
|
@@ -1350,6 +2931,13 @@ const WEB_LOADER_SOURCE = `
|
|
|
1350
2931
|
if (!auraRuntime) {
|
|
1351
2932
|
auraRuntime = createBrowserAuraSurface(cachedRuntimeConfig || {});
|
|
1352
2933
|
}
|
|
2934
|
+
if (auraRuntime && typeof auraRuntime.setManifest === 'function') {
|
|
2935
|
+
auraRuntime.setManifest(cachedManifest || {}, cachedRootUrl);
|
|
2936
|
+
}
|
|
2937
|
+
ensureCapabilityDeclarationSatisfied(
|
|
2938
|
+
cachedRuntimeConfig || {},
|
|
2939
|
+
auraRuntime && auraRuntime.aura ? auraRuntime.aura : globalRef.aura,
|
|
2940
|
+
);
|
|
1353
2941
|
if (typeof auraRuntime.mount === 'function') {
|
|
1354
2942
|
auraRuntime.mount(canvas, targetNode);
|
|
1355
2943
|
}
|