incanto 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/2d.d.ts +74 -6
- package/dist/2d.js +4 -4
- package/dist/3d.d.ts +174 -16
- package/dist/3d.js +4 -4
- package/dist/{audio-player-DqUR3XFs.d.ts → audio-player-DkBqRTs4.d.ts} +1 -1
- package/dist/{behavior-BAQq7HGM.d.ts → behavior-CWhW3oa6.d.ts} +54 -0
- package/dist/{create-game-CZHROKcT.js → create-game-BFESHv1X.js} +37 -25
- package/dist/{create-game-CMS7DiPi.js → create-game-D8UvwXme.js} +231 -8
- package/dist/debug.d.ts +1 -1
- package/dist/{duplicate-DP2WPYom.js → duplicate-BEvGBtb_.js} +1 -1
- package/dist/{gameplay-Ccruc3Wd.js → gameplay-CDFgSG6z.js} +293 -24
- package/dist/gameplay.d.ts +113 -2
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +139 -5
- package/dist/index.js +59 -6
- package/dist/{loader-CGs_G-r0.js → loader-B4OEXDZ8.js} +60 -0
- package/dist/{loader-Mo0KghCv.d.ts → loader-D2u0fVW2.d.ts} +1 -1
- package/dist/net.d.ts +1 -1
- package/dist/net.js +1 -1
- package/dist/{particle-sim-DYuSUxvK.js → particle-sim-CFkILGwh.js} +84 -3
- package/dist/{particle-sim-CbN4YUuH.d.ts → particle-sim-CwJ5rI_P.d.ts} +3 -0
- package/dist/{physics-2d-KuMWPTf6.js → physics-2d-KXn1N1jF.js} +95 -10
- package/dist/{physics-3d-CXOBOUKG.js → physics-3d-C58oQzTX.js} +121 -43
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-B0gq63VW.js → register-C35HDZpm.js} +2 -2
- package/dist/{register-DPEV9_9t.js → register-D71C4rDC.js} +76 -5
- package/dist/{register-BuUV1_KB.js → register-Dl_ixIJe.js} +275 -2
- package/dist/{register-02aSywx2.js → register-DvPHJdVj.js} +390 -59
- package/dist/test.d.ts +2 -2
- package/dist/test.js +10 -10
- package/editor/assets/{agent8-DUVZGcuO.js → agent8-DruKhR22.js} +1 -1
- package/editor/assets/index-D2qufqUo.js +7417 -0
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +847 -133
- package/skills/incanto-3d-models.md +24 -1
- package/skills/incanto-building-3d-games.md +35 -3
- package/skills/incanto-gameplay-behaviors.md +60 -0
- package/skills/incanto-hud.md +58 -0
- package/skills/incanto-node-reference.md +113 -0
- package/skills/incanto-physics-and-input.md +47 -0
- package/editor/assets/index-DsM2Yp9F.js +0 -7365
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as Node } from "./loader-
|
|
1
|
+
import { f as Node } from "./loader-B4OEXDZ8.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
4
4
|
import { l as registerNode } from "./registry-BVJ2HbCn.js";
|
|
@@ -500,6 +500,275 @@ var AudioPlayer = class extends Node {
|
|
|
500
500
|
}
|
|
501
501
|
};
|
|
502
502
|
//#endregion
|
|
503
|
+
//#region src/core/nodes/hud.ts
|
|
504
|
+
const ANCHOR_CSS = {
|
|
505
|
+
topLeft: "left:16px;top:16px;align-items:flex-start;",
|
|
506
|
+
top: "left:50%;top:16px;transform:translateX(-50%);align-items:center;",
|
|
507
|
+
topRight: "right:16px;top:16px;align-items:flex-end;",
|
|
508
|
+
left: "left:16px;top:50%;transform:translateY(-50%);align-items:flex-start;",
|
|
509
|
+
center: "left:50%;top:50%;transform:translate(-50%,-50%);align-items:center;",
|
|
510
|
+
right: "right:16px;top:50%;transform:translateY(-50%);align-items:flex-end;",
|
|
511
|
+
bottomLeft: "left:16px;bottom:16px;align-items:flex-start;",
|
|
512
|
+
bottom: "left:50%;bottom:16px;transform:translateX(-50%);align-items:center;",
|
|
513
|
+
bottomRight: "right:16px;bottom:16px;align-items:flex-end;"
|
|
514
|
+
};
|
|
515
|
+
const FONT = "600 14px system-ui, -apple-system, 'Segoe UI', sans-serif";
|
|
516
|
+
function hasDom() {
|
|
517
|
+
return typeof document !== "undefined";
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* The overlay container. One per scene is plenty; widgets mount into its
|
|
521
|
+
* anchor slots. `zIndex` lifts it above game canvases; the layer never eats
|
|
522
|
+
* pointer events (widgets that need clicks opt in individually).
|
|
523
|
+
*/
|
|
524
|
+
var HudLayer = class extends Node {
|
|
525
|
+
static typeName = "HudLayer";
|
|
526
|
+
static props = {
|
|
527
|
+
zIndex: { default: 100 },
|
|
528
|
+
visible: { default: true }
|
|
529
|
+
};
|
|
530
|
+
zIndex = 100;
|
|
531
|
+
visible = true;
|
|
532
|
+
/** @internal root overlay element (null headless). */
|
|
533
|
+
_element = null;
|
|
534
|
+
slots = /* @__PURE__ */ new Map();
|
|
535
|
+
onEnterTree() {
|
|
536
|
+
if (!hasDom()) return;
|
|
537
|
+
const el = document.createElement("div");
|
|
538
|
+
el.dataset.incantoHud = this.name;
|
|
539
|
+
el.style.cssText = `position:fixed;inset:0;pointer-events:none;z-index:${this.zIndex};font:${FONT};`;
|
|
540
|
+
document.body.appendChild(el);
|
|
541
|
+
this._element = el;
|
|
542
|
+
}
|
|
543
|
+
onExitTree() {
|
|
544
|
+
this._element?.remove();
|
|
545
|
+
this._element = null;
|
|
546
|
+
this.slots.clear();
|
|
547
|
+
}
|
|
548
|
+
update() {
|
|
549
|
+
if (this._element) this._element.style.display = this.visible ? "" : "none";
|
|
550
|
+
}
|
|
551
|
+
/** @internal Widgets mount into per-anchor flex columns. */
|
|
552
|
+
_slot(anchor) {
|
|
553
|
+
if (!this._element) return null;
|
|
554
|
+
let slot = this.slots.get(anchor);
|
|
555
|
+
if (!slot) {
|
|
556
|
+
slot = document.createElement("div");
|
|
557
|
+
slot.style.cssText = `position:absolute;display:flex;flex-direction:column;gap:8px;${ANCHOR_CSS[anchor] ?? ANCHOR_CSS.topLeft}`;
|
|
558
|
+
this._element.appendChild(slot);
|
|
559
|
+
this.slots.set(anchor, slot);
|
|
560
|
+
}
|
|
561
|
+
return slot;
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
/** Shared plumbing: mount into the parent HudLayer's anchor slot. */
|
|
565
|
+
var HudWidget = class extends Node {
|
|
566
|
+
static props = {
|
|
567
|
+
anchor: {
|
|
568
|
+
default: "topLeft",
|
|
569
|
+
options: [
|
|
570
|
+
"topLeft",
|
|
571
|
+
"top",
|
|
572
|
+
"topRight",
|
|
573
|
+
"left",
|
|
574
|
+
"center",
|
|
575
|
+
"right",
|
|
576
|
+
"bottomLeft",
|
|
577
|
+
"bottom",
|
|
578
|
+
"bottomRight"
|
|
579
|
+
]
|
|
580
|
+
},
|
|
581
|
+
visible: { default: true }
|
|
582
|
+
};
|
|
583
|
+
anchor = "topLeft";
|
|
584
|
+
visible = true;
|
|
585
|
+
/** @internal */
|
|
586
|
+
_element = null;
|
|
587
|
+
layer() {
|
|
588
|
+
for (let p = this.parent; p; p = p.parent) if (p instanceof HudLayer) return p;
|
|
589
|
+
return null;
|
|
590
|
+
}
|
|
591
|
+
onReady() {
|
|
592
|
+
if (!hasDom()) return;
|
|
593
|
+
const slot = this.layer()?._slot(this.anchor);
|
|
594
|
+
if (!slot) return;
|
|
595
|
+
this._element = this._build();
|
|
596
|
+
slot.appendChild(this._element);
|
|
597
|
+
}
|
|
598
|
+
onExitTree() {
|
|
599
|
+
this._element?.remove();
|
|
600
|
+
this._element = null;
|
|
601
|
+
}
|
|
602
|
+
update(_dt) {
|
|
603
|
+
if (!this._element) return;
|
|
604
|
+
this._element.style.display = this.visible ? "" : "none";
|
|
605
|
+
this._sync();
|
|
606
|
+
}
|
|
607
|
+
_sync() {}
|
|
608
|
+
};
|
|
609
|
+
/** A text line (score, timer, hints). Set `.text` from behaviors. */
|
|
610
|
+
var UiText = class extends HudWidget {
|
|
611
|
+
static typeName = "UiText";
|
|
612
|
+
static props = {
|
|
613
|
+
...HudWidget.props,
|
|
614
|
+
text: { default: "" },
|
|
615
|
+
size: { default: 16 },
|
|
616
|
+
color: { default: "#ffffff" },
|
|
617
|
+
shadow: { default: true }
|
|
618
|
+
};
|
|
619
|
+
text = "";
|
|
620
|
+
size = 16;
|
|
621
|
+
color = "#ffffff";
|
|
622
|
+
shadow = true;
|
|
623
|
+
last = "\0";
|
|
624
|
+
_build() {
|
|
625
|
+
const el = document.createElement("div");
|
|
626
|
+
el.style.cssText = `font-size:${this.size}px;color:${this.color};${this.shadow ? "text-shadow:0 1px 3px rgba(0,0,0,.7);" : ""}white-space:pre;`;
|
|
627
|
+
return el;
|
|
628
|
+
}
|
|
629
|
+
_sync() {
|
|
630
|
+
if (this.text !== this.last && this._element) {
|
|
631
|
+
this.last = this.text;
|
|
632
|
+
this._element.textContent = this.text;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
/** A labeled progress bar (health, stamina, reload, boss HP). */
|
|
637
|
+
var UiBar = class extends HudWidget {
|
|
638
|
+
static typeName = "UiBar";
|
|
639
|
+
static props = {
|
|
640
|
+
...HudWidget.props,
|
|
641
|
+
value: { default: 100 },
|
|
642
|
+
max: { default: 100 },
|
|
643
|
+
width: { default: 180 },
|
|
644
|
+
height: { default: 14 },
|
|
645
|
+
color: { default: "#4ade80" },
|
|
646
|
+
lowColor: { default: "#ef4444" },
|
|
647
|
+
lowThreshold: { default: .3 },
|
|
648
|
+
background: { default: "rgba(0,0,0,0.5)" },
|
|
649
|
+
label: { default: "" }
|
|
650
|
+
};
|
|
651
|
+
value = 100;
|
|
652
|
+
max = 100;
|
|
653
|
+
width = 180;
|
|
654
|
+
height = 14;
|
|
655
|
+
color = "#4ade80";
|
|
656
|
+
lowColor = "#ef4444";
|
|
657
|
+
lowThreshold = .3;
|
|
658
|
+
background = "rgba(0,0,0,0.5)";
|
|
659
|
+
label = "";
|
|
660
|
+
fill = null;
|
|
661
|
+
lastRatio = -1;
|
|
662
|
+
/** Current fill ratio 0..1 (what the bar shows). */
|
|
663
|
+
get ratio() {
|
|
664
|
+
return this.max > 0 ? Math.min(1, Math.max(0, this.value / this.max)) : 0;
|
|
665
|
+
}
|
|
666
|
+
_build() {
|
|
667
|
+
const wrap = document.createElement("div");
|
|
668
|
+
wrap.style.cssText = "display:flex;align-items:center;gap:6px;";
|
|
669
|
+
if (this.label) {
|
|
670
|
+
const tag = document.createElement("span");
|
|
671
|
+
tag.textContent = this.label;
|
|
672
|
+
tag.style.cssText = "color:#fff;font-size:12px;text-shadow:0 1px 3px rgba(0,0,0,.7);";
|
|
673
|
+
wrap.appendChild(tag);
|
|
674
|
+
}
|
|
675
|
+
const track = document.createElement("div");
|
|
676
|
+
track.style.cssText = `width:${this.width}px;height:${this.height}px;background:${this.background};border-radius:${this.height / 2}px;overflow:hidden;`;
|
|
677
|
+
this.fill = document.createElement("div");
|
|
678
|
+
this.fill.style.cssText = `height:100%;width:100%;background:${this.color};border-radius:inherit;transition:width .15s;`;
|
|
679
|
+
track.appendChild(this.fill);
|
|
680
|
+
wrap.appendChild(track);
|
|
681
|
+
return wrap;
|
|
682
|
+
}
|
|
683
|
+
_sync() {
|
|
684
|
+
const r = this.ratio;
|
|
685
|
+
if (r === this.lastRatio || !this.fill) return;
|
|
686
|
+
this.lastRatio = r;
|
|
687
|
+
this.fill.style.width = `${r * 100}%`;
|
|
688
|
+
this.fill.style.background = r <= this.lowThreshold ? this.lowColor : this.color;
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
/**
|
|
692
|
+
* Center-screen announcements ("WAVE 2", "YOU DIED", "LEVEL UP") with fade
|
|
693
|
+
* in/out and a queue — call `.show(text, { color, seconds })`; `sticky:true`
|
|
694
|
+
* (seconds: 0) keeps it until the next show(). Emits `bannerShown(text)`.
|
|
695
|
+
*/
|
|
696
|
+
var UiBanner = class extends HudWidget {
|
|
697
|
+
static typeName = "UiBanner";
|
|
698
|
+
static signals = ["bannerShown"];
|
|
699
|
+
static props = {
|
|
700
|
+
...HudWidget.props,
|
|
701
|
+
anchor: {
|
|
702
|
+
default: "center",
|
|
703
|
+
options: [
|
|
704
|
+
"topLeft",
|
|
705
|
+
"top",
|
|
706
|
+
"topRight",
|
|
707
|
+
"left",
|
|
708
|
+
"center",
|
|
709
|
+
"right",
|
|
710
|
+
"bottomLeft",
|
|
711
|
+
"bottom",
|
|
712
|
+
"bottomRight"
|
|
713
|
+
]
|
|
714
|
+
},
|
|
715
|
+
size: { default: 42 },
|
|
716
|
+
seconds: { default: 2 }
|
|
717
|
+
};
|
|
718
|
+
anchor = "center";
|
|
719
|
+
size = 42;
|
|
720
|
+
/** Default display time (per-show override via options). */
|
|
721
|
+
seconds = 2;
|
|
722
|
+
queue = [];
|
|
723
|
+
current = null;
|
|
724
|
+
remaining = 0;
|
|
725
|
+
/** What the banner is showing right now ('' when idle) — test-friendly. */
|
|
726
|
+
get showing() {
|
|
727
|
+
return this.current?.text ?? "";
|
|
728
|
+
}
|
|
729
|
+
show(text, opts) {
|
|
730
|
+
this.queue.push({
|
|
731
|
+
text,
|
|
732
|
+
color: opts?.color ?? "#ffffff",
|
|
733
|
+
seconds: opts?.seconds ?? this.seconds
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
/** Drop everything (scene transitions). */
|
|
737
|
+
clear() {
|
|
738
|
+
this.queue.length = 0;
|
|
739
|
+
this.current = null;
|
|
740
|
+
this.remaining = 0;
|
|
741
|
+
if (this._element) this._element.style.opacity = "0";
|
|
742
|
+
}
|
|
743
|
+
_build() {
|
|
744
|
+
const el = document.createElement("div");
|
|
745
|
+
el.style.cssText = `font-size:${this.size}px;font-weight:800;color:#fff;text-shadow:0 2px 12px rgba(0,0,0,.8);opacity:0;transition:opacity .25s;text-align:center;`;
|
|
746
|
+
return el;
|
|
747
|
+
}
|
|
748
|
+
update(dt) {
|
|
749
|
+
super.update(dt);
|
|
750
|
+
if (this.current) {
|
|
751
|
+
if (this.current.seconds > 0) {
|
|
752
|
+
this.remaining -= dt;
|
|
753
|
+
if (this.remaining <= 0) {
|
|
754
|
+
this.current = null;
|
|
755
|
+
if (this._element) this._element.style.opacity = "0";
|
|
756
|
+
}
|
|
757
|
+
} else if (this.queue.length > 0) this.current = null;
|
|
758
|
+
}
|
|
759
|
+
if (!this.current && this.queue.length > 0) {
|
|
760
|
+
this.current = this.queue.shift();
|
|
761
|
+
this.remaining = this.current.seconds;
|
|
762
|
+
if (this._element) {
|
|
763
|
+
this._element.textContent = this.current.text;
|
|
764
|
+
this._element.style.color = this.current.color;
|
|
765
|
+
this._element.style.opacity = "1";
|
|
766
|
+
}
|
|
767
|
+
this.emit("bannerShown", this.current.text);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
//#endregion
|
|
503
772
|
//#region src/core/nodes/timer.ts
|
|
504
773
|
/**
|
|
505
774
|
* The canonical serializable game clock — never `setTimeout` in game logic.
|
|
@@ -556,6 +825,10 @@ function registerCoreNodes() {
|
|
|
556
825
|
registerNode(Node);
|
|
557
826
|
registerNode(Timer);
|
|
558
827
|
registerNode(AudioPlayer);
|
|
828
|
+
registerNode(HudLayer);
|
|
829
|
+
registerNode(UiText);
|
|
830
|
+
registerNode(UiBar);
|
|
831
|
+
registerNode(UiBanner);
|
|
559
832
|
}
|
|
560
833
|
//#endregion
|
|
561
|
-
export {
|
|
834
|
+
export { UiBar as a, ROLLOFF_MODELS as c, SFX_PRESETS as d, SFX_PRESET_NAMES as f, UiBanner as i, spatialGain as l, Timer as n, UiText as o, synthSfx as p, HudLayer as r, AudioPlayer as s, registerCoreNodes as t, spatialPan as u };
|