@combos-fun/engine 0.0.38 → 0.0.40
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/engine.cjs.js +231 -3
- package/dist/engine.cjs.js.map +1 -1
- package/dist/engine.cjs.prod.js +1 -1
- package/dist/engine.d.ts +78 -4
- package/dist/engine.esm.js +230 -4
- package/dist/engine.esm.js.map +1 -1
- package/package.json +7 -3
- package/references/bootstrap-examples.md +59 -32
- package/references/public-api.md +2 -2
package/dist/engine.cjs.js
CHANGED
|
@@ -1001,7 +1001,7 @@ class Scene extends GameObject {
|
|
|
1001
1001
|
}
|
|
1002
1002
|
|
|
1003
1003
|
/** Generated at build from package.json */
|
|
1004
|
-
const version = "0.0.
|
|
1004
|
+
const version = "0.0.40";
|
|
1005
1005
|
|
|
1006
1006
|
/**
|
|
1007
1007
|
* Sent to `window.parent` after each `System.init` completes during `Game.addSystem`
|
|
@@ -1642,6 +1642,117 @@ class Progress extends EventEmitter__default.default {
|
|
|
1642
1642
|
}
|
|
1643
1643
|
}
|
|
1644
1644
|
|
|
1645
|
+
const SLOT_DEFAULT_TYPE = {
|
|
1646
|
+
image: 'png',
|
|
1647
|
+
json: 'json',
|
|
1648
|
+
tex: 'tex',
|
|
1649
|
+
ske: 'ske',
|
|
1650
|
+
audio: 'audio',
|
|
1651
|
+
video: 'video',
|
|
1652
|
+
model: 'glb',
|
|
1653
|
+
mtl: 'mtl',
|
|
1654
|
+
bin: 'bin',
|
|
1655
|
+
};
|
|
1656
|
+
const EXT_TO_TYPE = {
|
|
1657
|
+
png: 'png',
|
|
1658
|
+
jpg: 'jpg',
|
|
1659
|
+
jpeg: 'jpeg',
|
|
1660
|
+
webp: 'webp',
|
|
1661
|
+
json: 'json',
|
|
1662
|
+
tex: 'tex',
|
|
1663
|
+
ske: 'ske',
|
|
1664
|
+
mp3: 'audio',
|
|
1665
|
+
wav: 'audio',
|
|
1666
|
+
aac: 'audio',
|
|
1667
|
+
ogg: 'audio',
|
|
1668
|
+
mp4: 'video',
|
|
1669
|
+
webm: 'video',
|
|
1670
|
+
glb: 'glb',
|
|
1671
|
+
gltf: 'gltf',
|
|
1672
|
+
fbx: 'fbx',
|
|
1673
|
+
obj: 'obj',
|
|
1674
|
+
mtl: 'mtl',
|
|
1675
|
+
stl: 'stl',
|
|
1676
|
+
dae: 'dae',
|
|
1677
|
+
ply: 'ply',
|
|
1678
|
+
bin: 'bin',
|
|
1679
|
+
};
|
|
1680
|
+
function extensionOf(url) {
|
|
1681
|
+
const path = url.split('?')[0].split('#')[0];
|
|
1682
|
+
const dot = path.lastIndexOf('.');
|
|
1683
|
+
if (dot < 0)
|
|
1684
|
+
return '';
|
|
1685
|
+
return path.slice(dot + 1).toLowerCase();
|
|
1686
|
+
}
|
|
1687
|
+
function typeFromUrl(url, slot) {
|
|
1688
|
+
return EXT_TO_TYPE[extensionOf(url)] || SLOT_DEFAULT_TYPE[slot] || 'png';
|
|
1689
|
+
}
|
|
1690
|
+
function defaultSlotForResourceType(resourceType) {
|
|
1691
|
+
if (resourceType === 'AUDIO')
|
|
1692
|
+
return 'audio';
|
|
1693
|
+
if (resourceType === 'VIDEO')
|
|
1694
|
+
return 'video';
|
|
1695
|
+
if (resourceType === 'MODEL' || resourceType === 'GLB')
|
|
1696
|
+
return 'model';
|
|
1697
|
+
return 'image';
|
|
1698
|
+
}
|
|
1699
|
+
function wrapSlot(slot, value, resourceName) {
|
|
1700
|
+
if (typeof value === 'string') {
|
|
1701
|
+
const url = value.trim();
|
|
1702
|
+
if (!url) {
|
|
1703
|
+
throw missingUrlError(resourceName, slot);
|
|
1704
|
+
}
|
|
1705
|
+
return { type: typeFromUrl(url, slot), url };
|
|
1706
|
+
}
|
|
1707
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1708
|
+
throw new Error(`Resource "${resourceName}" src.${slot} must be a url string or { type, url }.`);
|
|
1709
|
+
}
|
|
1710
|
+
const slotValue = value;
|
|
1711
|
+
if (slotValue.type === 'data') {
|
|
1712
|
+
return slotValue;
|
|
1713
|
+
}
|
|
1714
|
+
const url = typeof slotValue.url === 'string' ? slotValue.url.trim() : '';
|
|
1715
|
+
if (!url) {
|
|
1716
|
+
throw missingUrlError(resourceName, slot);
|
|
1717
|
+
}
|
|
1718
|
+
return {
|
|
1719
|
+
...slotValue,
|
|
1720
|
+
type: slotValue.type || typeFromUrl(url, slot),
|
|
1721
|
+
url,
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
function missingUrlError(resourceName, slot) {
|
|
1725
|
+
return new Error(`Resource "${resourceName}" src.${slot}.url is required. ` +
|
|
1726
|
+
`Use { type, url } (e.g. { type: "webp", url: "https://..." }). ` +
|
|
1727
|
+
`A flat path string is also accepted and will be normalized.`);
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Accept the documented `{ type, url }` slots, plus the common guesses
|
|
1731
|
+
* `src: "file.png"` and `src: { image: "a.webp", json: "a.json" }`.
|
|
1732
|
+
*/
|
|
1733
|
+
function normalizeResourceSrc(src, resourceType, resourceName = '(unnamed)') {
|
|
1734
|
+
if (src == null) {
|
|
1735
|
+
throw new Error(`Resource "${resourceName}" src is required.`);
|
|
1736
|
+
}
|
|
1737
|
+
if (typeof src === 'string') {
|
|
1738
|
+
const slot = defaultSlotForResourceType(resourceType);
|
|
1739
|
+
return { [slot]: wrapSlot(slot, src, resourceName) };
|
|
1740
|
+
}
|
|
1741
|
+
if (typeof src !== 'object' || Array.isArray(src)) {
|
|
1742
|
+
throw new Error(`Resource "${resourceName}" src must be a url string or a slot object.`);
|
|
1743
|
+
}
|
|
1744
|
+
const out = {};
|
|
1745
|
+
for (const [slot, value] of Object.entries(src)) {
|
|
1746
|
+
if (value == null)
|
|
1747
|
+
continue;
|
|
1748
|
+
out[slot] = wrapSlot(slot, value, resourceName);
|
|
1749
|
+
}
|
|
1750
|
+
if (Object.keys(out).length === 0) {
|
|
1751
|
+
throw new Error(`Resource "${resourceName}" src has no loadable slots.`);
|
|
1752
|
+
}
|
|
1753
|
+
return out;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1645
1756
|
const resourceLoader = {
|
|
1646
1757
|
AbstractLoadStrategy: resourceLoader$1.AbstractLoadStrategy,
|
|
1647
1758
|
AudioLoadStrategy: resourceLoader$1.AudioLoadStrategy,
|
|
@@ -1656,6 +1767,102 @@ const resourceLoader = {
|
|
|
1656
1767
|
ResourceState: resourceLoader$1.ResourceState
|
|
1657
1768
|
};
|
|
1658
1769
|
|
|
1770
|
+
function isFrameMap(frames) {
|
|
1771
|
+
return !!frames && typeof frames === 'object' && !Array.isArray(frames);
|
|
1772
|
+
}
|
|
1773
|
+
function frameFromPackedItem(item) {
|
|
1774
|
+
const frame = item.frame;
|
|
1775
|
+
if (!frame || typeof frame !== 'object')
|
|
1776
|
+
return null;
|
|
1777
|
+
return {
|
|
1778
|
+
...item,
|
|
1779
|
+
frame: frame,
|
|
1780
|
+
rotated: Boolean(item.rotated),
|
|
1781
|
+
trimmed: Boolean(item.trimmed),
|
|
1782
|
+
spriteSourceSize: item.spriteSourceSize,
|
|
1783
|
+
sourceSize: item.sourceSize,
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
function collectArrayFrames(list, frames, animations) {
|
|
1787
|
+
for (const raw of list) {
|
|
1788
|
+
if (!raw || typeof raw !== 'object')
|
|
1789
|
+
continue;
|
|
1790
|
+
const item = raw;
|
|
1791
|
+
const name = String(item.filename || item.name || '');
|
|
1792
|
+
if (!name)
|
|
1793
|
+
continue;
|
|
1794
|
+
const packed = frameFromPackedItem(item);
|
|
1795
|
+
if (!packed)
|
|
1796
|
+
continue;
|
|
1797
|
+
frames[name] = packed;
|
|
1798
|
+
const slash = name.lastIndexOf('/');
|
|
1799
|
+
if (slash > 0) {
|
|
1800
|
+
const anim = name.slice(0, slash);
|
|
1801
|
+
if (!animations[anim])
|
|
1802
|
+
animations[anim] = [];
|
|
1803
|
+
if (!animations[anim].includes(name))
|
|
1804
|
+
animations[anim].push(name);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1809
|
+
* Pixi `Spritesheet` reads `data.meta.scale` and a name→frame `frames` map.
|
|
1810
|
+
* TexturePacker multi-atlas (`textures[].frames` as an array) is accepted and
|
|
1811
|
+
* rewritten to that hash. Always returns a `meta.scale` so construction cannot
|
|
1812
|
+
* throw `Cannot read properties of undefined (reading 'scale')`.
|
|
1813
|
+
*/
|
|
1814
|
+
function normalizeSpritesheetData(raw) {
|
|
1815
|
+
if (!raw || typeof raw !== 'object') {
|
|
1816
|
+
return { frames: {}, animations: {}, meta: { scale: 1 } };
|
|
1817
|
+
}
|
|
1818
|
+
const json = raw;
|
|
1819
|
+
if (isFrameMap(json.frames)) {
|
|
1820
|
+
return {
|
|
1821
|
+
...json,
|
|
1822
|
+
frames: json.frames,
|
|
1823
|
+
animations: { ...(json.animations || {}) },
|
|
1824
|
+
meta: { scale: 1, ...(json.meta || {}) },
|
|
1825
|
+
};
|
|
1826
|
+
}
|
|
1827
|
+
const frames = {};
|
|
1828
|
+
const animations = { ...(json.animations || {}) };
|
|
1829
|
+
if (Array.isArray(json.textures)) {
|
|
1830
|
+
for (const sheet of json.textures) {
|
|
1831
|
+
if (!sheet || typeof sheet !== 'object')
|
|
1832
|
+
continue;
|
|
1833
|
+
if (Array.isArray(sheet.frames)) {
|
|
1834
|
+
collectArrayFrames(sheet.frames, frames, animations);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
const first = json.textures[0] || {};
|
|
1838
|
+
const scale = first.scale ?? json.meta?.scale ?? 1;
|
|
1839
|
+
return {
|
|
1840
|
+
frames,
|
|
1841
|
+
animations,
|
|
1842
|
+
meta: {
|
|
1843
|
+
scale: typeof scale === 'number' || typeof scale === 'string' ? scale : 1,
|
|
1844
|
+
image: typeof first.image === 'string' ? first.image : undefined,
|
|
1845
|
+
size: first.size,
|
|
1846
|
+
format: first.format,
|
|
1847
|
+
...(json.meta || {}),
|
|
1848
|
+
},
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1851
|
+
if (Array.isArray(json.frames)) {
|
|
1852
|
+
collectArrayFrames(json.frames, frames, animations);
|
|
1853
|
+
return {
|
|
1854
|
+
frames,
|
|
1855
|
+
animations,
|
|
1856
|
+
meta: { scale: 1, ...(json.meta || {}) },
|
|
1857
|
+
};
|
|
1858
|
+
}
|
|
1859
|
+
return {
|
|
1860
|
+
frames: {},
|
|
1861
|
+
animations,
|
|
1862
|
+
meta: { scale: 1, ...(json.meta || {}) },
|
|
1863
|
+
};
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1659
1866
|
/** Resource type */
|
|
1660
1867
|
exports.RESOURCE_TYPE = void 0;
|
|
1661
1868
|
(function (RESOURCE_TYPE) {
|
|
@@ -1665,6 +1872,7 @@ exports.RESOURCE_TYPE = void 0;
|
|
|
1665
1872
|
RESOURCE_TYPE["AUDIO"] = "AUDIO";
|
|
1666
1873
|
RESOURCE_TYPE["VIDEO"] = "VIDEO";
|
|
1667
1874
|
RESOURCE_TYPE["GLB"] = "GLB";
|
|
1875
|
+
RESOURCE_TYPE["MODEL"] = "MODEL";
|
|
1668
1876
|
})(exports.RESOURCE_TYPE || (exports.RESOURCE_TYPE = {}));
|
|
1669
1877
|
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('json', resourceLoader$1.XhrResponseType.Json);
|
|
1670
1878
|
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('tex', resourceLoader$1.XhrResponseType.Json);
|
|
@@ -1675,6 +1883,13 @@ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('aac', resourceLoader$1.Xhr
|
|
|
1675
1883
|
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('ogg', resourceLoader$1.XhrResponseType.Buffer);
|
|
1676
1884
|
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('glb', resourceLoader$1.XhrResponseType.Buffer);
|
|
1677
1885
|
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('gltf', resourceLoader$1.XhrResponseType.Json);
|
|
1886
|
+
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('fbx', resourceLoader$1.XhrResponseType.Buffer);
|
|
1887
|
+
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('stl', resourceLoader$1.XhrResponseType.Buffer);
|
|
1888
|
+
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('ply', resourceLoader$1.XhrResponseType.Buffer);
|
|
1889
|
+
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('bin', resourceLoader$1.XhrResponseType.Buffer);
|
|
1890
|
+
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('obj', resourceLoader$1.XhrResponseType.Text);
|
|
1891
|
+
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('mtl', resourceLoader$1.XhrResponseType.Text);
|
|
1892
|
+
resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('dae', resourceLoader$1.XhrResponseType.Text);
|
|
1678
1893
|
const RESOURCE_TYPE_STRATEGY = {
|
|
1679
1894
|
png: resourceLoader$1.ImageLoadStrategy,
|
|
1680
1895
|
jpg: resourceLoader$1.ImageLoadStrategy,
|
|
@@ -1687,6 +1902,13 @@ const RESOURCE_TYPE_STRATEGY = {
|
|
|
1687
1902
|
video: resourceLoader$1.VideoLoadStrategy,
|
|
1688
1903
|
glb: resourceLoader$1.XhrLoadStrategy,
|
|
1689
1904
|
gltf: resourceLoader$1.XhrLoadStrategy,
|
|
1905
|
+
fbx: resourceLoader$1.XhrLoadStrategy,
|
|
1906
|
+
obj: resourceLoader$1.XhrLoadStrategy,
|
|
1907
|
+
mtl: resourceLoader$1.XhrLoadStrategy,
|
|
1908
|
+
stl: resourceLoader$1.XhrLoadStrategy,
|
|
1909
|
+
dae: resourceLoader$1.XhrLoadStrategy,
|
|
1910
|
+
ply: resourceLoader$1.XhrLoadStrategy,
|
|
1911
|
+
bin: resourceLoader$1.XhrLoadStrategy,
|
|
1690
1912
|
};
|
|
1691
1913
|
/**
|
|
1692
1914
|
* Resource manager
|
|
@@ -1733,8 +1955,11 @@ class Resource extends EventEmitter__default.default {
|
|
|
1733
1955
|
console.warn(res.name + ' was already added');
|
|
1734
1956
|
continue;
|
|
1735
1957
|
}
|
|
1736
|
-
this.resourcesMap[res.name] =
|
|
1737
|
-
|
|
1958
|
+
this.resourcesMap[res.name] = {
|
|
1959
|
+
...res,
|
|
1960
|
+
src: normalizeResourceSrc(res.src, String(res.type), res.name),
|
|
1961
|
+
data: {},
|
|
1962
|
+
};
|
|
1738
1963
|
}
|
|
1739
1964
|
}
|
|
1740
1965
|
/** dd resource preprocesser*/
|
|
@@ -1823,6 +2048,7 @@ class Resource extends EventEmitter__default.default {
|
|
|
1823
2048
|
for (const handler of this.preProcessResourceHandlers) {
|
|
1824
2049
|
handler(res);
|
|
1825
2050
|
}
|
|
2051
|
+
res.src = normalizeResourceSrc(res.src, String(res.type), res.name);
|
|
1826
2052
|
for (const key in res.src) {
|
|
1827
2053
|
const resourceType = res.src[key].type;
|
|
1828
2054
|
if (resourceType === 'data') {
|
|
@@ -1949,6 +2175,8 @@ exports.componentObserver = componentObserver;
|
|
|
1949
2175
|
exports.decorators = decorators;
|
|
1950
2176
|
exports.isAllowedMessageOrigin = isAllowedMessageOrigin;
|
|
1951
2177
|
exports.mergeAllowedMessageOrigins = mergeAllowedMessageOrigins;
|
|
2178
|
+
exports.normalizeResourceSrc = normalizeResourceSrc;
|
|
2179
|
+
exports.normalizeSpritesheetData = normalizeSpritesheetData;
|
|
1952
2180
|
exports.parseSetPlayingMessage = parseSetPlayingMessage;
|
|
1953
2181
|
exports.postParentGameReady = postParentGameReady;
|
|
1954
2182
|
exports.postParentGameState = postParentGameState;
|