@auraindustry/aurajs 0.0.3 → 0.0.5
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 +36 -0
- package/package.json +1 -1
- package/src/build-contract.mjs +658 -7
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @auraindustry/aurajs
|
|
2
|
+
|
|
3
|
+
> Alpha status: AuraJS is currently in alpha and is not safe for production use yet.
|
|
4
|
+
|
|
5
|
+
Write games in JavaScript and build native binaries for macOS, Linux, and Windows.
|
|
6
|
+
|
|
7
|
+
## Create A New Game
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g auramaxx
|
|
11
|
+
auramaxx create my-game
|
|
12
|
+
cd my-game
|
|
13
|
+
npm run dev
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Publish And Play
|
|
17
|
+
|
|
18
|
+
In a scaffolded AuraJS game:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm run publish
|
|
22
|
+
npm run play
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`npm run publish` maps to `npx auramaxx publish` in generated projects.
|
|
26
|
+
|
|
27
|
+
## API Surfaces
|
|
28
|
+
|
|
29
|
+
- React embedding: `@auraindustry/aurajs/react`
|
|
30
|
+
- Web runtime helpers: `@auraindustry/aurajs/web`
|
|
31
|
+
|
|
32
|
+
## Docs
|
|
33
|
+
|
|
34
|
+
- Repo README: <https://github.com/Aura-Industry/aurajs>
|
|
35
|
+
- Core API: <https://github.com/Aura-Industry/aurajs/blob/main/packages/aurascript/docs/api-contract-v1.md>
|
|
36
|
+
- 3D API: <https://github.com/Aura-Industry/aurajs/blob/main/packages/aurascript/docs/api-contract-3d-v2.md>
|
package/package.json
CHANGED
package/src/build-contract.mjs
CHANGED
|
@@ -309,12 +309,25 @@ const WEB_INDEX_HTML = [
|
|
|
309
309
|
' <meta charset="utf-8" />',
|
|
310
310
|
' <meta name="viewport" content="width=device-width, initial-scale=1" />',
|
|
311
311
|
' <title>AuraJS Web Build</title>',
|
|
312
|
+
' <style>',
|
|
313
|
+
' html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; background: #060912; }',
|
|
314
|
+
' #aura-root { width: 100vw; height: 100vh; display: grid; place-items: center; }',
|
|
315
|
+
' #aura-canvas { display: block; max-width: 100%; max-height: 100%; }',
|
|
316
|
+
' </style>',
|
|
312
317
|
'</head>',
|
|
313
318
|
'<body>',
|
|
314
319
|
' <div id="aura-root">',
|
|
315
320
|
' <canvas id="aura-canvas"></canvas>',
|
|
316
321
|
' </div>',
|
|
317
322
|
' <script src="./js/aura-web-loader.js"></script>',
|
|
323
|
+
' <script>',
|
|
324
|
+
' window.addEventListener("load", function () {',
|
|
325
|
+
' if (!window.AuraWebLoader || typeof window.AuraWebLoader.mount !== "function") return;',
|
|
326
|
+
' window.AuraWebLoader.mount("#aura-root", { rootUrl: ".", mount: "#aura-root" }).catch(function (error) {',
|
|
327
|
+
' console.error(error);',
|
|
328
|
+
' });',
|
|
329
|
+
' });',
|
|
330
|
+
' </script>',
|
|
318
331
|
'</body>',
|
|
319
332
|
'</html>',
|
|
320
333
|
].join('\n');
|
|
@@ -337,6 +350,7 @@ const WEB_LOADER_SOURCE = `
|
|
|
337
350
|
let cachedManifest = null;
|
|
338
351
|
let cachedRuntimeConfig = null;
|
|
339
352
|
let mountedRuntime = null;
|
|
353
|
+
let auraRuntime = null;
|
|
340
354
|
|
|
341
355
|
function normalizeCount(value) {
|
|
342
356
|
const numeric = Number(value);
|
|
@@ -434,6 +448,135 @@ const WEB_LOADER_SOURCE = `
|
|
|
434
448
|
return path.replace(/\\\\/g, '/').replace(/^\\.\\//, '');
|
|
435
449
|
}
|
|
436
450
|
|
|
451
|
+
function clampUnit(value, fallback) {
|
|
452
|
+
const numeric = Number(value);
|
|
453
|
+
if (!Number.isFinite(numeric)) return fallback;
|
|
454
|
+
if (numeric <= 0) return 0;
|
|
455
|
+
if (numeric >= 1) return 1;
|
|
456
|
+
return numeric;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function createUnitColor(r, g, b, a) {
|
|
460
|
+
return {
|
|
461
|
+
r: clampUnit(r, 0),
|
|
462
|
+
g: clampUnit(g, 0),
|
|
463
|
+
b: clampUnit(b, 0),
|
|
464
|
+
a: clampUnit(a == null ? 1 : a, 1)
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function createByteColor(r, g, b, a) {
|
|
469
|
+
return {
|
|
470
|
+
r: Math.max(0, Math.min(255, Math.round(Number(r) || 0))),
|
|
471
|
+
g: Math.max(0, Math.min(255, Math.round(Number(g) || 0))),
|
|
472
|
+
b: Math.max(0, Math.min(255, Math.round(Number(b) || 0))),
|
|
473
|
+
a: Math.max(0, Math.min(255, Math.round(Number.isFinite(Number(a)) ? Number(a) : 255)))
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function normalizeColor(value, fallback) {
|
|
478
|
+
const source = value && typeof value === 'object' ? value : null;
|
|
479
|
+
const base = fallback && typeof fallback === 'object' ? fallback : createUnitColor(1, 1, 1, 1);
|
|
480
|
+
if (!source) {
|
|
481
|
+
return createUnitColor(base.r, base.g, base.b, base.a);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const rawR = Number(source.r);
|
|
485
|
+
const rawG = Number(source.g);
|
|
486
|
+
const rawB = Number(source.b);
|
|
487
|
+
const rawA = source.a == null ? base.a : Number(source.a);
|
|
488
|
+
const treatAsByteRange = [rawR, rawG, rawB, rawA].some((component) => Number.isFinite(component) && component > 1);
|
|
489
|
+
|
|
490
|
+
if (treatAsByteRange) {
|
|
491
|
+
return createUnitColor(
|
|
492
|
+
Number.isFinite(rawR) ? rawR / 255 : base.r,
|
|
493
|
+
Number.isFinite(rawG) ? rawG / 255 : base.g,
|
|
494
|
+
Number.isFinite(rawB) ? rawB / 255 : base.b,
|
|
495
|
+
Number.isFinite(rawA) ? rawA / 255 : base.a
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return createUnitColor(
|
|
500
|
+
Number.isFinite(rawR) ? rawR : base.r,
|
|
501
|
+
Number.isFinite(rawG) ? rawG : base.g,
|
|
502
|
+
Number.isFinite(rawB) ? rawB : base.b,
|
|
503
|
+
Number.isFinite(rawA) ? rawA : base.a
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function colorToCss(value, fallback) {
|
|
508
|
+
const normalized = normalizeColor(value, fallback);
|
|
509
|
+
return 'rgba('
|
|
510
|
+
+ Math.round(normalized.r * 255) + ', '
|
|
511
|
+
+ Math.round(normalized.g * 255) + ', '
|
|
512
|
+
+ Math.round(normalized.b * 255) + ', '
|
|
513
|
+
+ normalized.a + ')';
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function normalizeCanvasSize(value, fallback) {
|
|
517
|
+
const numeric = Number(value);
|
|
518
|
+
if (!Number.isFinite(numeric) || numeric <= 0) return fallback;
|
|
519
|
+
return Math.max(1, Math.floor(numeric));
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function normalizePositiveNumber(value, fallback) {
|
|
523
|
+
const numeric = Number(value);
|
|
524
|
+
if (!Number.isFinite(numeric) || numeric <= 0) return fallback;
|
|
525
|
+
return numeric;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function normalizeTextAlign(value) {
|
|
529
|
+
if (value === 'center' || value === 'right' || value === 'left') {
|
|
530
|
+
return value;
|
|
531
|
+
}
|
|
532
|
+
return 'left';
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function normalizeKeyName(value) {
|
|
536
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
537
|
+
return null;
|
|
538
|
+
}
|
|
539
|
+
const key = value.toLowerCase();
|
|
540
|
+
switch (key) {
|
|
541
|
+
case ' ':
|
|
542
|
+
case 'spacebar':
|
|
543
|
+
return 'space';
|
|
544
|
+
case 'left':
|
|
545
|
+
case 'arrowleft':
|
|
546
|
+
return 'arrowleft';
|
|
547
|
+
case 'right':
|
|
548
|
+
case 'arrowright':
|
|
549
|
+
return 'arrowright';
|
|
550
|
+
case 'up':
|
|
551
|
+
case 'arrowup':
|
|
552
|
+
return 'arrowup';
|
|
553
|
+
case 'down':
|
|
554
|
+
case 'arrowdown':
|
|
555
|
+
return 'arrowdown';
|
|
556
|
+
case 'return':
|
|
557
|
+
return 'enter';
|
|
558
|
+
default:
|
|
559
|
+
return key;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function rectIntersects(a, b) {
|
|
564
|
+
const ax = Number(a && a.x);
|
|
565
|
+
const ay = Number(a && a.y);
|
|
566
|
+
const aw = Number(a && a.w);
|
|
567
|
+
const ah = Number(a && a.h);
|
|
568
|
+
const bx = Number(b && b.x);
|
|
569
|
+
const by = Number(b && b.y);
|
|
570
|
+
const bw = Number(b && b.w);
|
|
571
|
+
const bh = Number(b && b.h);
|
|
572
|
+
|
|
573
|
+
if (![ax, ay, aw, ah, bx, by, bw, bh].every((value) => Number.isFinite(value))) {
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return ax < bx + bw && ax + aw > bx && ay < by + bh && ay + ah > by;
|
|
578
|
+
}
|
|
579
|
+
|
|
437
580
|
function resolveTarget(target) {
|
|
438
581
|
if (typeof target === 'string') {
|
|
439
582
|
return document.querySelector(target);
|
|
@@ -484,17 +627,503 @@ const WEB_LOADER_SOURCE = `
|
|
|
484
627
|
});
|
|
485
628
|
}
|
|
486
629
|
|
|
487
|
-
function
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
630
|
+
function createBrowserAuraSurface(runtimeConfig) {
|
|
631
|
+
const defaultColor = createUnitColor(1, 1, 1, 1);
|
|
632
|
+
let currentRuntimeConfig = runtimeConfig && typeof runtimeConfig === 'object' ? runtimeConfig : {};
|
|
633
|
+
let currentCanvasConfig = currentRuntimeConfig.canvas && typeof currentRuntimeConfig.canvas === 'object'
|
|
634
|
+
? currentRuntimeConfig.canvas
|
|
635
|
+
: {};
|
|
636
|
+
|
|
637
|
+
const auraRef = globalRef.aura && typeof globalRef.aura === 'object'
|
|
638
|
+
? globalRef.aura
|
|
639
|
+
: {};
|
|
640
|
+
globalRef.aura = auraRef;
|
|
641
|
+
|
|
642
|
+
const inputState = {
|
|
643
|
+
down: new Set(),
|
|
644
|
+
pendingPressed: new Set(),
|
|
645
|
+
pendingReleased: new Set(),
|
|
646
|
+
framePressed: new Set(),
|
|
647
|
+
frameReleased: new Set()
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
const runtime = {
|
|
651
|
+
canvas: null,
|
|
652
|
+
mountTarget: null,
|
|
653
|
+
context2d: null,
|
|
654
|
+
configuredWidth: normalizeCanvasSize(currentCanvasConfig.width, 1280),
|
|
655
|
+
configuredHeight: normalizeCanvasSize(currentCanvasConfig.height, 720),
|
|
656
|
+
resizeMode: currentCanvasConfig.resizeMode === 'fixed' ? 'fixed' : 'fit-container',
|
|
657
|
+
pixelRatio: 1,
|
|
658
|
+
width: normalizeCanvasSize(currentCanvasConfig.width, 1280),
|
|
659
|
+
height: normalizeCanvasSize(currentCanvasConfig.height, 720),
|
|
660
|
+
transformDepth: 0,
|
|
661
|
+
listenersAttached: false,
|
|
662
|
+
keydownListener: null,
|
|
663
|
+
keyupListener: null,
|
|
664
|
+
blurListener: null,
|
|
665
|
+
resizeListener: null
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
function ensureStyleObject(node) {
|
|
669
|
+
if (!node || typeof node !== 'object') return null;
|
|
670
|
+
if (!node.style || typeof node.style !== 'object') {
|
|
671
|
+
node.style = {};
|
|
672
|
+
}
|
|
673
|
+
return node.style;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function ensureCanvasContext() {
|
|
677
|
+
if (!runtime.canvas) return null;
|
|
678
|
+
if (!runtime.context2d && typeof runtime.canvas.getContext === 'function') {
|
|
679
|
+
runtime.context2d = runtime.canvas.getContext('2d');
|
|
680
|
+
}
|
|
681
|
+
return runtime.context2d;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function syncCanvasSize(notifyResize) {
|
|
685
|
+
let width = runtime.configuredWidth;
|
|
686
|
+
let height = runtime.configuredHeight;
|
|
687
|
+
if (runtime.resizeMode === 'fit-container') {
|
|
688
|
+
const containerWidth = runtime.mountTarget
|
|
689
|
+
? normalizeCanvasSize(runtime.mountTarget.clientWidth, 0)
|
|
690
|
+
: 0;
|
|
691
|
+
const containerHeight = runtime.mountTarget
|
|
692
|
+
? normalizeCanvasSize(runtime.mountTarget.clientHeight, 0)
|
|
693
|
+
: 0;
|
|
694
|
+
if (containerWidth > 0 && containerHeight > 0) {
|
|
695
|
+
width = containerWidth;
|
|
696
|
+
height = containerHeight;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
runtime.width = normalizeCanvasSize(width, runtime.configuredWidth);
|
|
701
|
+
runtime.height = normalizeCanvasSize(height, runtime.configuredHeight);
|
|
702
|
+
runtime.pixelRatio = Math.min(Math.max(normalizePositiveNumber(globalRef.devicePixelRatio, 1), 1), 2);
|
|
703
|
+
|
|
704
|
+
auraRef.window.width = runtime.width;
|
|
705
|
+
auraRef.window.height = runtime.height;
|
|
706
|
+
auraRef.window.pixelRatio = runtime.pixelRatio;
|
|
707
|
+
|
|
708
|
+
if (runtime.canvas) {
|
|
709
|
+
runtime.canvas.width = Math.max(1, Math.round(runtime.width * runtime.pixelRatio));
|
|
710
|
+
runtime.canvas.height = Math.max(1, Math.round(runtime.height * runtime.pixelRatio));
|
|
711
|
+
runtime.canvas.tabIndex = 0;
|
|
712
|
+
const style = ensureStyleObject(runtime.canvas);
|
|
713
|
+
if (style) {
|
|
714
|
+
style.width = runtime.width + 'px';
|
|
715
|
+
style.height = runtime.height + 'px';
|
|
716
|
+
style.display = 'block';
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
if (notifyResize && typeof auraRef.onResize === 'function') {
|
|
721
|
+
auraRef.onResize(runtime.width, runtime.height);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
function resetDrawState() {
|
|
726
|
+
const ctx = ensureCanvasContext();
|
|
727
|
+
if (!ctx) return;
|
|
728
|
+
if (typeof ctx.setTransform === 'function') {
|
|
729
|
+
ctx.setTransform(runtime.pixelRatio, 0, 0, runtime.pixelRatio, 0, 0);
|
|
730
|
+
} else {
|
|
731
|
+
if (typeof ctx.resetTransform === 'function') {
|
|
732
|
+
ctx.resetTransform();
|
|
733
|
+
}
|
|
734
|
+
if (typeof ctx.scale === 'function') {
|
|
735
|
+
ctx.scale(runtime.pixelRatio, runtime.pixelRatio);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
runtime.transformDepth = 0;
|
|
739
|
+
ctx.globalAlpha = 1;
|
|
740
|
+
ctx.textAlign = 'left';
|
|
741
|
+
ctx.textBaseline = 'top';
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
function applyFont(options) {
|
|
745
|
+
const ctx = ensureCanvasContext();
|
|
746
|
+
const source = options && typeof options === 'object' ? options : {};
|
|
747
|
+
const size = normalizePositiveNumber(source.size, 16);
|
|
748
|
+
const family = typeof source.font === 'string' && source.font.trim().length > 0
|
|
749
|
+
? source.font.trim()
|
|
750
|
+
: 'sans-serif';
|
|
751
|
+
if (ctx) {
|
|
752
|
+
ctx.font = size + 'px ' + family;
|
|
753
|
+
ctx.textAlign = normalizeTextAlign(source.align);
|
|
754
|
+
ctx.textBaseline = 'top';
|
|
755
|
+
}
|
|
756
|
+
return { size, align: normalizeTextAlign(source.align) };
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
function attachListeners() {
|
|
760
|
+
if (runtime.listenersAttached) return;
|
|
761
|
+
runtime.listenersAttached = true;
|
|
762
|
+
|
|
763
|
+
runtime.keydownListener = function (event) {
|
|
764
|
+
const key = normalizeKeyName(event && (event.key || event.code));
|
|
765
|
+
if (!key) return;
|
|
766
|
+
if (!inputState.down.has(key)) {
|
|
767
|
+
inputState.pendingPressed.add(key);
|
|
768
|
+
}
|
|
769
|
+
inputState.down.add(key);
|
|
770
|
+
if (event && typeof event.preventDefault === 'function' && (key === 'space' || key.startsWith('arrow'))) {
|
|
771
|
+
event.preventDefault();
|
|
772
|
+
}
|
|
773
|
+
};
|
|
774
|
+
|
|
775
|
+
runtime.keyupListener = function (event) {
|
|
776
|
+
const key = normalizeKeyName(event && (event.key || event.code));
|
|
777
|
+
if (!key) return;
|
|
778
|
+
inputState.down.delete(key);
|
|
779
|
+
inputState.pendingReleased.add(key);
|
|
780
|
+
if (event && typeof event.preventDefault === 'function' && (key === 'space' || key.startsWith('arrow'))) {
|
|
781
|
+
event.preventDefault();
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
runtime.blurListener = function () {
|
|
786
|
+
inputState.down.clear();
|
|
787
|
+
inputState.pendingPressed.clear();
|
|
788
|
+
inputState.pendingReleased.clear();
|
|
789
|
+
inputState.framePressed.clear();
|
|
790
|
+
inputState.frameReleased.clear();
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
runtime.resizeListener = function () {
|
|
794
|
+
syncCanvasSize(true);
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
if (typeof globalRef.addEventListener === 'function') {
|
|
798
|
+
globalRef.addEventListener('keydown', runtime.keydownListener);
|
|
799
|
+
globalRef.addEventListener('keyup', runtime.keyupListener);
|
|
800
|
+
globalRef.addEventListener('blur', runtime.blurListener);
|
|
801
|
+
globalRef.addEventListener('resize', runtime.resizeListener);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
function detachListeners() {
|
|
806
|
+
if (!runtime.listenersAttached) return;
|
|
807
|
+
runtime.listenersAttached = false;
|
|
808
|
+
if (typeof globalRef.removeEventListener === 'function') {
|
|
809
|
+
globalRef.removeEventListener('keydown', runtime.keydownListener);
|
|
810
|
+
globalRef.removeEventListener('keyup', runtime.keyupListener);
|
|
811
|
+
globalRef.removeEventListener('blur', runtime.blurListener);
|
|
812
|
+
globalRef.removeEventListener('resize', runtime.resizeListener);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
auraRef.setup = typeof auraRef.setup === 'function' ? auraRef.setup : null;
|
|
817
|
+
auraRef.update = typeof auraRef.update === 'function' ? auraRef.update : null;
|
|
818
|
+
auraRef.draw = typeof auraRef.draw === 'function' ? auraRef.draw : null;
|
|
819
|
+
auraRef.onResize = typeof auraRef.onResize === 'function' ? auraRef.onResize : null;
|
|
820
|
+
auraRef.onFocus = typeof auraRef.onFocus === 'function' ? auraRef.onFocus : null;
|
|
821
|
+
auraRef.onBlur = typeof auraRef.onBlur === 'function' ? auraRef.onBlur : null;
|
|
822
|
+
auraRef.onQuit = typeof auraRef.onQuit === 'function' ? auraRef.onQuit : null;
|
|
823
|
+
|
|
824
|
+
auraRef.rgba = function (r, g, b, a) {
|
|
825
|
+
return createUnitColor(r, g, b, a == null ? 1 : a);
|
|
826
|
+
};
|
|
827
|
+
auraRef.color = auraRef.rgba;
|
|
828
|
+
auraRef.Color = auraRef.Color && typeof auraRef.Color === 'object'
|
|
829
|
+
? auraRef.Color
|
|
830
|
+
: {
|
|
831
|
+
WHITE: createUnitColor(1, 1, 1, 1),
|
|
832
|
+
BLACK: createUnitColor(0, 0, 0, 1),
|
|
833
|
+
RED: createUnitColor(1, 0, 0, 1),
|
|
834
|
+
YELLOW: createUnitColor(1, 1, 0, 1),
|
|
835
|
+
TRANSPARENT: createUnitColor(0, 0, 0, 0)
|
|
836
|
+
};
|
|
837
|
+
auraRef.colors = auraRef.colors && typeof auraRef.colors === 'object'
|
|
838
|
+
? auraRef.colors
|
|
839
|
+
: {
|
|
840
|
+
white: createByteColor(255, 255, 255, 255),
|
|
841
|
+
black: createByteColor(0, 0, 0, 255),
|
|
842
|
+
red: createByteColor(255, 0, 0, 255),
|
|
843
|
+
yellow: createByteColor(255, 255, 0, 255),
|
|
844
|
+
transparent: createByteColor(0, 0, 0, 0)
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
auraRef.window = auraRef.window && typeof auraRef.window === 'object' ? auraRef.window : {};
|
|
848
|
+
auraRef.window.width = runtime.width;
|
|
849
|
+
auraRef.window.height = runtime.height;
|
|
850
|
+
auraRef.window.pixelRatio = runtime.pixelRatio;
|
|
851
|
+
auraRef.window.fps = 60;
|
|
852
|
+
auraRef.window.setTitle = function (title) {
|
|
853
|
+
if (typeof title === 'string') {
|
|
854
|
+
document.title = title;
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
auraRef.window.setSize = function (width, height) {
|
|
858
|
+
runtime.configuredWidth = normalizeCanvasSize(width, runtime.configuredWidth);
|
|
859
|
+
runtime.configuredHeight = normalizeCanvasSize(height, runtime.configuredHeight);
|
|
860
|
+
syncCanvasSize(true);
|
|
861
|
+
resetDrawState();
|
|
862
|
+
return true;
|
|
863
|
+
};
|
|
864
|
+
auraRef.window.setFullscreen = function () {
|
|
865
|
+
return false;
|
|
866
|
+
};
|
|
867
|
+
auraRef.window.getSize = function () {
|
|
868
|
+
return { width: runtime.width, height: runtime.height };
|
|
869
|
+
};
|
|
870
|
+
auraRef.window.getPixelRatio = function () {
|
|
871
|
+
return runtime.pixelRatio;
|
|
872
|
+
};
|
|
873
|
+
auraRef.window.getFPS = function () {
|
|
874
|
+
return auraRef.window.fps;
|
|
875
|
+
};
|
|
876
|
+
auraRef.window.close = function () {
|
|
877
|
+
return true;
|
|
878
|
+
};
|
|
879
|
+
|
|
880
|
+
auraRef.collision = auraRef.collision && typeof auraRef.collision === 'object' ? auraRef.collision : {};
|
|
881
|
+
auraRef.collision.rectRect = function (a, b) {
|
|
882
|
+
return rectIntersects(a, b);
|
|
883
|
+
};
|
|
884
|
+
auraRef.collide = auraRef.collide && typeof auraRef.collide === 'object' ? auraRef.collide : auraRef.collision;
|
|
885
|
+
auraRef.collide.rectRect = auraRef.collision.rectRect;
|
|
886
|
+
|
|
887
|
+
auraRef.input = auraRef.input && typeof auraRef.input === 'object' ? auraRef.input : {};
|
|
888
|
+
auraRef.input.isDown = function (name) {
|
|
889
|
+
const key = normalizeKeyName(name);
|
|
890
|
+
return key ? inputState.down.has(key) : false;
|
|
891
|
+
};
|
|
892
|
+
auraRef.input.isPressed = function (name) {
|
|
893
|
+
const key = normalizeKeyName(name);
|
|
894
|
+
return key ? inputState.framePressed.has(key) : false;
|
|
895
|
+
};
|
|
896
|
+
auraRef.input.isReleased = function (name) {
|
|
897
|
+
const key = normalizeKeyName(name);
|
|
898
|
+
return key ? inputState.frameReleased.has(key) : false;
|
|
899
|
+
};
|
|
900
|
+
auraRef.input.isKeyDown = function (name) {
|
|
901
|
+
return auraRef.input.isDown(name);
|
|
902
|
+
};
|
|
903
|
+
auraRef.input.isKeyPressed = function (name) {
|
|
904
|
+
return auraRef.input.isPressed(name);
|
|
905
|
+
};
|
|
906
|
+
auraRef.input.isKeyReleased = function (name) {
|
|
907
|
+
return auraRef.input.isReleased(name);
|
|
908
|
+
};
|
|
909
|
+
auraRef.input.mouse = auraRef.input.mouse && typeof auraRef.input.mouse === 'object' ? auraRef.input.mouse : {};
|
|
910
|
+
auraRef.input.mouse.x = Number(auraRef.input.mouse.x) || 0;
|
|
911
|
+
auraRef.input.mouse.y = Number(auraRef.input.mouse.y) || 0;
|
|
912
|
+
auraRef.input.mouse.scroll = Number(auraRef.input.mouse.scroll) || 0;
|
|
913
|
+
auraRef.input.mouse.isDown = function () { return false; };
|
|
914
|
+
auraRef.input.mouse.isPressed = function () { return false; };
|
|
915
|
+
auraRef.input.mouse.isReleased = function () { return false; };
|
|
916
|
+
auraRef.input.getMousePosition = function () {
|
|
917
|
+
return { x: auraRef.input.mouse.x, y: auraRef.input.mouse.y };
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
auraRef.assets = auraRef.assets && typeof auraRef.assets === 'object' ? auraRef.assets : {};
|
|
921
|
+
auraRef.assets.load = typeof auraRef.assets.load === 'function'
|
|
922
|
+
? auraRef.assets.load
|
|
923
|
+
: async function () { return true; };
|
|
924
|
+
auraRef.assets.exists = typeof auraRef.assets.exists === 'function'
|
|
925
|
+
? auraRef.assets.exists
|
|
926
|
+
: function () { return false; };
|
|
927
|
+
auraRef.assets.image = typeof auraRef.assets.image === 'function'
|
|
928
|
+
? auraRef.assets.image
|
|
929
|
+
: function (name) { return { kind: 'image', name: String(name || '') }; };
|
|
930
|
+
auraRef.assets.sound = typeof auraRef.assets.sound === 'function'
|
|
931
|
+
? auraRef.assets.sound
|
|
932
|
+
: function (name) { return { kind: 'sound', name: String(name || '') }; };
|
|
933
|
+
auraRef.assets.text = typeof auraRef.assets.text === 'function'
|
|
934
|
+
? auraRef.assets.text
|
|
935
|
+
: function () { return ''; };
|
|
936
|
+
auraRef.assets.json = typeof auraRef.assets.json === 'function'
|
|
937
|
+
? auraRef.assets.json
|
|
938
|
+
: function () { return {}; };
|
|
939
|
+
auraRef.assets.bytes = typeof auraRef.assets.bytes === 'function'
|
|
940
|
+
? auraRef.assets.bytes
|
|
941
|
+
: function () { return new Uint8Array(); };
|
|
942
|
+
|
|
943
|
+
auraRef.draw2d = auraRef.draw2d && typeof auraRef.draw2d === 'object' ? auraRef.draw2d : {};
|
|
944
|
+
auraRef.draw2d.clear = function (colorOrR, g, b, a) {
|
|
945
|
+
const ctx = ensureCanvasContext();
|
|
946
|
+
if (!ctx) return;
|
|
947
|
+
const fillColor = arguments.length > 1
|
|
948
|
+
? createUnitColor(colorOrR, g, b, a == null ? 1 : a)
|
|
949
|
+
: normalizeColor(colorOrR, createUnitColor(0, 0, 0, 1));
|
|
950
|
+
resetDrawState();
|
|
951
|
+
ctx.clearRect(0, 0, runtime.width, runtime.height);
|
|
952
|
+
ctx.fillStyle = colorToCss(fillColor, createUnitColor(0, 0, 0, 1));
|
|
953
|
+
ctx.fillRect(0, 0, runtime.width, runtime.height);
|
|
954
|
+
};
|
|
955
|
+
auraRef.draw2d.rect = function (x, y, w, h, color) {
|
|
956
|
+
const ctx = ensureCanvasContext();
|
|
957
|
+
if (!ctx) return;
|
|
958
|
+
ctx.strokeStyle = colorToCss(color, defaultColor);
|
|
959
|
+
ctx.lineWidth = 1;
|
|
960
|
+
ctx.strokeRect(Number(x) || 0, Number(y) || 0, Number(w) || 0, Number(h) || 0);
|
|
961
|
+
};
|
|
962
|
+
auraRef.draw2d.rectOutline = auraRef.draw2d.rect;
|
|
963
|
+
auraRef.draw2d.rectFill = function (x, y, w, h, color) {
|
|
964
|
+
const ctx = ensureCanvasContext();
|
|
965
|
+
if (!ctx) return;
|
|
966
|
+
ctx.fillStyle = colorToCss(color, defaultColor);
|
|
967
|
+
ctx.fillRect(Number(x) || 0, Number(y) || 0, Number(w) || 0, Number(h) || 0);
|
|
968
|
+
};
|
|
969
|
+
auraRef.draw2d.circle = function (x, y, radius, color) {
|
|
970
|
+
const ctx = ensureCanvasContext();
|
|
971
|
+
if (!ctx) return;
|
|
972
|
+
ctx.beginPath();
|
|
973
|
+
ctx.arc(Number(x) || 0, Number(y) || 0, Math.max(0, Number(radius) || 0), 0, Math.PI * 2);
|
|
974
|
+
ctx.strokeStyle = colorToCss(color, defaultColor);
|
|
975
|
+
ctx.lineWidth = 1;
|
|
976
|
+
ctx.stroke();
|
|
977
|
+
};
|
|
978
|
+
auraRef.draw2d.circleFill = function (x, y, radius, color) {
|
|
979
|
+
const ctx = ensureCanvasContext();
|
|
980
|
+
if (!ctx) return;
|
|
981
|
+
ctx.beginPath();
|
|
982
|
+
ctx.arc(Number(x) || 0, Number(y) || 0, Math.max(0, Number(radius) || 0), 0, Math.PI * 2);
|
|
983
|
+
ctx.fillStyle = colorToCss(color, defaultColor);
|
|
984
|
+
ctx.fill();
|
|
985
|
+
};
|
|
986
|
+
auraRef.draw2d.line = function (x1, y1, x2, y2, color, width) {
|
|
987
|
+
const ctx = ensureCanvasContext();
|
|
988
|
+
if (!ctx) return;
|
|
989
|
+
ctx.beginPath();
|
|
990
|
+
ctx.moveTo(Number(x1) || 0, Number(y1) || 0);
|
|
991
|
+
ctx.lineTo(Number(x2) || 0, Number(y2) || 0);
|
|
992
|
+
ctx.strokeStyle = colorToCss(color, defaultColor);
|
|
993
|
+
ctx.lineWidth = normalizePositiveNumber(width, 1);
|
|
994
|
+
ctx.stroke();
|
|
995
|
+
};
|
|
996
|
+
auraRef.draw2d.text = function (text, x, y, options) {
|
|
997
|
+
const ctx = ensureCanvasContext();
|
|
998
|
+
if (!ctx) return;
|
|
999
|
+
const config = applyFont(options);
|
|
1000
|
+
const source = options && typeof options === 'object' ? options : {};
|
|
1001
|
+
ctx.fillStyle = colorToCss(source.color, defaultColor);
|
|
1002
|
+
ctx.textAlign = config.align;
|
|
1003
|
+
ctx.textBaseline = 'top';
|
|
1004
|
+
ctx.fillText(String(text == null ? '' : text), Number(x) || 0, Number(y) || 0);
|
|
1005
|
+
};
|
|
1006
|
+
auraRef.draw2d.measureText = function (text, options) {
|
|
1007
|
+
const source = options && typeof options === 'object' ? options : {};
|
|
1008
|
+
const size = normalizePositiveNumber(source.size, 16);
|
|
1009
|
+
const ctx = ensureCanvasContext();
|
|
1010
|
+
if (!ctx) {
|
|
1011
|
+
const fallbackWidth = String(text == null ? '' : text).length * size * 0.6;
|
|
1012
|
+
return { width: Number(fallbackWidth.toFixed(3)), height: size };
|
|
1013
|
+
}
|
|
1014
|
+
applyFont(options);
|
|
1015
|
+
const metrics = ctx.measureText(String(text == null ? '' : text));
|
|
1016
|
+
const measuredWidth = Number.isFinite(metrics && metrics.width)
|
|
1017
|
+
? metrics.width
|
|
1018
|
+
: String(text == null ? '' : text).length * size * 0.6;
|
|
1019
|
+
return { width: Number(measuredWidth.toFixed(3)), height: size };
|
|
1020
|
+
};
|
|
1021
|
+
auraRef.draw2d.image = typeof auraRef.draw2d.image === 'function'
|
|
1022
|
+
? auraRef.draw2d.image
|
|
1023
|
+
: function () { return true; };
|
|
1024
|
+
auraRef.draw2d.sprite = typeof auraRef.draw2d.sprite === 'function'
|
|
1025
|
+
? auraRef.draw2d.sprite
|
|
1026
|
+
: function () { return true; };
|
|
1027
|
+
auraRef.draw2d.pushTransform = function () {
|
|
1028
|
+
const ctx = ensureCanvasContext();
|
|
1029
|
+
if (!ctx || typeof ctx.save !== 'function') return;
|
|
1030
|
+
runtime.transformDepth += 1;
|
|
1031
|
+
ctx.save();
|
|
1032
|
+
};
|
|
1033
|
+
auraRef.draw2d.popTransform = function () {
|
|
1034
|
+
const ctx = ensureCanvasContext();
|
|
1035
|
+
if (!ctx || typeof ctx.restore !== 'function' || runtime.transformDepth <= 0) return;
|
|
1036
|
+
runtime.transformDepth -= 1;
|
|
1037
|
+
ctx.restore();
|
|
1038
|
+
};
|
|
1039
|
+
auraRef.draw2d.push = auraRef.draw2d.pushTransform;
|
|
1040
|
+
auraRef.draw2d.pop = auraRef.draw2d.popTransform;
|
|
1041
|
+
auraRef.draw2d.translate = function (x, y) {
|
|
1042
|
+
const ctx = ensureCanvasContext();
|
|
1043
|
+
if (!ctx || typeof ctx.translate !== 'function') return;
|
|
1044
|
+
ctx.translate(Number(x) || 0, Number(y) || 0);
|
|
1045
|
+
};
|
|
1046
|
+
auraRef.draw2d.rotate = function (angle) {
|
|
1047
|
+
const ctx = ensureCanvasContext();
|
|
1048
|
+
if (!ctx || typeof ctx.rotate !== 'function') return;
|
|
1049
|
+
ctx.rotate(Number(angle) || 0);
|
|
1050
|
+
};
|
|
1051
|
+
auraRef.draw2d.scale = function (x, y) {
|
|
1052
|
+
const ctx = ensureCanvasContext();
|
|
1053
|
+
if (!ctx || typeof ctx.scale !== 'function') return;
|
|
1054
|
+
const scaleX = normalizePositiveNumber(x, 1);
|
|
1055
|
+
const scaleY = normalizePositiveNumber(y, scaleX);
|
|
1056
|
+
ctx.scale(scaleX, scaleY);
|
|
1057
|
+
};
|
|
1058
|
+
|
|
1059
|
+
return {
|
|
1060
|
+
aura: auraRef,
|
|
1061
|
+
setRuntimeConfig(nextRuntimeConfig) {
|
|
1062
|
+
currentRuntimeConfig = nextRuntimeConfig && typeof nextRuntimeConfig === 'object' ? nextRuntimeConfig : {};
|
|
1063
|
+
currentCanvasConfig = currentRuntimeConfig.canvas && typeof currentRuntimeConfig.canvas === 'object'
|
|
1064
|
+
? currentRuntimeConfig.canvas
|
|
1065
|
+
: {};
|
|
1066
|
+
runtime.configuredWidth = normalizeCanvasSize(currentCanvasConfig.width, runtime.configuredWidth);
|
|
1067
|
+
runtime.configuredHeight = normalizeCanvasSize(currentCanvasConfig.height, runtime.configuredHeight);
|
|
1068
|
+
runtime.resizeMode = currentCanvasConfig.resizeMode === 'fixed' ? 'fixed' : 'fit-container';
|
|
1069
|
+
syncCanvasSize(false);
|
|
1070
|
+
},
|
|
1071
|
+
mount(canvas, mountTarget) {
|
|
1072
|
+
runtime.canvas = canvas || runtime.canvas;
|
|
1073
|
+
runtime.mountTarget = mountTarget || runtime.mountTarget;
|
|
1074
|
+
ensureCanvasContext();
|
|
1075
|
+
syncCanvasSize(false);
|
|
1076
|
+
resetDrawState();
|
|
1077
|
+
attachListeners();
|
|
1078
|
+
inputState.down.clear();
|
|
1079
|
+
inputState.pendingPressed.clear();
|
|
1080
|
+
inputState.pendingReleased.clear();
|
|
1081
|
+
inputState.framePressed.clear();
|
|
1082
|
+
inputState.frameReleased.clear();
|
|
1083
|
+
if (runtime.canvas && typeof runtime.canvas.focus === 'function') {
|
|
1084
|
+
runtime.canvas.focus();
|
|
1085
|
+
}
|
|
1086
|
+
return true;
|
|
1087
|
+
},
|
|
1088
|
+
beginFrame() {
|
|
1089
|
+
inputState.framePressed = new Set(inputState.pendingPressed);
|
|
1090
|
+
inputState.frameReleased = new Set(inputState.pendingReleased);
|
|
1091
|
+
inputState.pendingPressed.clear();
|
|
1092
|
+
inputState.pendingReleased.clear();
|
|
1093
|
+
resetDrawState();
|
|
1094
|
+
},
|
|
1095
|
+
endFrame() {
|
|
1096
|
+
const ctx = ensureCanvasContext();
|
|
1097
|
+
if (ctx && typeof ctx.restore === 'function') {
|
|
1098
|
+
while (runtime.transformDepth > 0) {
|
|
1099
|
+
runtime.transformDepth -= 1;
|
|
1100
|
+
ctx.restore();
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
},
|
|
1104
|
+
unmount() {
|
|
1105
|
+
detachListeners();
|
|
1106
|
+
inputState.down.clear();
|
|
1107
|
+
inputState.pendingPressed.clear();
|
|
1108
|
+
inputState.pendingReleased.clear();
|
|
1109
|
+
inputState.framePressed.clear();
|
|
1110
|
+
inputState.frameReleased.clear();
|
|
1111
|
+
runtime.mountTarget = null;
|
|
1112
|
+
runtime.canvas = null;
|
|
1113
|
+
runtime.context2d = null;
|
|
1114
|
+
runtime.transformDepth = 0;
|
|
1115
|
+
return true;
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
491
1118
|
}
|
|
492
1119
|
|
|
493
1120
|
function createDeterministicBootstrap() {
|
|
494
1121
|
return async function bootstrap(input) {
|
|
495
|
-
const auraRef =
|
|
496
|
-
?
|
|
497
|
-
: (globalRef.aura
|
|
1122
|
+
const auraRef = auraRuntime && auraRuntime.aura
|
|
1123
|
+
? auraRuntime.aura
|
|
1124
|
+
: (globalRef.aura && typeof globalRef.aura === 'object'
|
|
1125
|
+
? globalRef.aura
|
|
1126
|
+
: (globalRef.aura = {}));
|
|
498
1127
|
const runtimeConfig = input && typeof input.runtimeConfig === 'object' && input.runtimeConfig
|
|
499
1128
|
? input.runtimeConfig
|
|
500
1129
|
: {};
|
|
@@ -571,6 +1200,9 @@ const WEB_LOADER_SOURCE = `
|
|
|
571
1200
|
runtimeState.lastDeltaSeconds = fixedDeltaSeconds;
|
|
572
1201
|
|
|
573
1202
|
try {
|
|
1203
|
+
if (auraRuntime && typeof auraRuntime.beginFrame === 'function') {
|
|
1204
|
+
auraRuntime.beginFrame();
|
|
1205
|
+
}
|
|
574
1206
|
if (typeof auraRef.update === 'function') {
|
|
575
1207
|
auraRef.update(fixedDeltaSeconds);
|
|
576
1208
|
runtimeState.updateCalls += 1;
|
|
@@ -579,6 +1211,9 @@ const WEB_LOADER_SOURCE = `
|
|
|
579
1211
|
auraRef.draw();
|
|
580
1212
|
runtimeState.drawCalls += 1;
|
|
581
1213
|
}
|
|
1214
|
+
if (auraRuntime && typeof auraRuntime.endFrame === 'function') {
|
|
1215
|
+
auraRuntime.endFrame();
|
|
1216
|
+
}
|
|
582
1217
|
} catch (error) {
|
|
583
1218
|
runtimeState.running = false;
|
|
584
1219
|
syncLifecycle();
|
|
@@ -616,6 +1251,9 @@ const WEB_LOADER_SOURCE = `
|
|
|
616
1251
|
cancelFrame(runtimeState.rafHandle);
|
|
617
1252
|
runtimeState.rafHandle = null;
|
|
618
1253
|
}
|
|
1254
|
+
if (auraRuntime && typeof auraRuntime.unmount === 'function') {
|
|
1255
|
+
auraRuntime.unmount();
|
|
1256
|
+
}
|
|
619
1257
|
syncLifecycle();
|
|
620
1258
|
return true;
|
|
621
1259
|
}
|
|
@@ -662,6 +1300,12 @@ const WEB_LOADER_SOURCE = `
|
|
|
662
1300
|
ensureManifestValid(cachedManifest);
|
|
663
1301
|
ensureRuntimeConfigValid(cachedRuntimeConfig);
|
|
664
1302
|
|
|
1303
|
+
if (!auraRuntime) {
|
|
1304
|
+
auraRuntime = createBrowserAuraSurface(cachedRuntimeConfig);
|
|
1305
|
+
} else if (typeof auraRuntime.setRuntimeConfig === 'function') {
|
|
1306
|
+
auraRuntime.setRuntimeConfig(cachedRuntimeConfig);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
665
1309
|
const bundleEntry = normalizePath(cachedManifest.entrypoints.bundle);
|
|
666
1310
|
if (bundleEntry.length === 0) {
|
|
667
1311
|
throw createError('web_entrypoint_missing', 'Bundle entrypoint is empty.', 'loader', false, {});
|
|
@@ -703,6 +1347,13 @@ const WEB_LOADER_SOURCE = `
|
|
|
703
1347
|
throw createError('web_loader_mount_failed', 'Canvas target was not found.', 'loader', true, {});
|
|
704
1348
|
}
|
|
705
1349
|
|
|
1350
|
+
if (!auraRuntime) {
|
|
1351
|
+
auraRuntime = createBrowserAuraSurface(cachedRuntimeConfig || {});
|
|
1352
|
+
}
|
|
1353
|
+
if (typeof auraRuntime.mount === 'function') {
|
|
1354
|
+
auraRuntime.mount(canvas, targetNode);
|
|
1355
|
+
}
|
|
1356
|
+
|
|
706
1357
|
const bootstrap = resolveBootstrap();
|
|
707
1358
|
if (typeof bootstrap !== 'function') {
|
|
708
1359
|
throw createError('web_runtime_bootstrap_missing', 'Bundle did not expose required bootstrap function.', 'runtime', false, {});
|