jailedthreejs 0.9.2-beta.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/README.md +141 -0
- package/dist/NoScope.js +208 -0
- package/dist/Train.js +349 -0
- package/dist/artist.js +492 -0
- package/dist/cell.js +508 -0
- package/dist/index.js +12 -0
- package/dist/main.js +136 -0
- package/dist/utils.js +300 -0
- package/package.json +41 -0
package/dist/utils.js
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// utils.js
|
|
2
|
+
//
|
|
3
|
+
// - Keyframe rule collection
|
|
4
|
+
// - Class map for tag → THREE constructor
|
|
5
|
+
// - Asset loading / caching
|
|
6
|
+
// - Small array utilities
|
|
7
|
+
|
|
8
|
+
import * as THREE from 'three';
|
|
9
|
+
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
10
|
+
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
|
|
11
|
+
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js';
|
|
12
|
+
|
|
13
|
+
export let AllKeyFramesMap = new Map();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Collect all @keyframes rules from loaded stylesheets.
|
|
17
|
+
*
|
|
18
|
+
* @returns {Map<string, CSSKeyframesRule>}
|
|
19
|
+
*/
|
|
20
|
+
export function gatherKeyFrame_MAP() {
|
|
21
|
+
AllKeyFramesMap.clear();
|
|
22
|
+
|
|
23
|
+
const KEYFRAMES_TYPES = new Set();
|
|
24
|
+
if (typeof CSSRule !== 'undefined') {
|
|
25
|
+
if ('KEYFRAMES_RULE' in CSSRule) KEYFRAMES_TYPES.add(CSSRule.KEYFRAMES_RULE);
|
|
26
|
+
if ('WEBKIT_KEYFRAMES_RULE' in CSSRule) KEYFRAMES_TYPES.add(CSSRule.WEBKIT_KEYFRAMES_RULE);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for (const sheet of document.styleSheets) {
|
|
30
|
+
let rules;
|
|
31
|
+
try {
|
|
32
|
+
rules = sheet.cssRules;
|
|
33
|
+
} catch {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
for (const rule of rules) {
|
|
37
|
+
if (KEYFRAMES_TYPES.has(rule.type)) {
|
|
38
|
+
AllKeyFramesMap.set(rule.name, rule);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return AllKeyFramesMap;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get a CSSKeyframesRule by name, rescanning stylesheets each call.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} AnimName
|
|
50
|
+
*/
|
|
51
|
+
export function getAnimationMap(AnimName) {
|
|
52
|
+
if (!AnimName) return undefined;
|
|
53
|
+
gatherKeyFrame_MAP();
|
|
54
|
+
return AllKeyFramesMap.get(AnimName);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* ───────────────── CLASS MAP ───────────────── */
|
|
58
|
+
|
|
59
|
+
let classMap = null;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Build a map of tag-name-like keys → THREE.Object3D constructors.
|
|
63
|
+
*/
|
|
64
|
+
function buildClassMap() {
|
|
65
|
+
classMap = Object.getOwnPropertyNames(THREE)
|
|
66
|
+
.filter(key => {
|
|
67
|
+
const C = THREE[key];
|
|
68
|
+
return typeof C === 'function' && C.prototype instanceof THREE.Object3D;
|
|
69
|
+
})
|
|
70
|
+
.reduce((m, key) => {
|
|
71
|
+
m[key.toUpperCase()] = THREE[key];
|
|
72
|
+
return m;
|
|
73
|
+
}, Object.create(null));
|
|
74
|
+
|
|
75
|
+
// include base Object3D explicitly
|
|
76
|
+
classMap.OBJECT3D = THREE.Object3D;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get the cached class map, building it on first call.
|
|
81
|
+
*
|
|
82
|
+
* @returns {Object.<string,Function>}
|
|
83
|
+
*/
|
|
84
|
+
export function getClassMap() {
|
|
85
|
+
if (!classMap) buildClassMap();
|
|
86
|
+
return classMap;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ───────────────── ASSET MAP ───────────────── */
|
|
90
|
+
|
|
91
|
+
const assetMap = new Map();
|
|
92
|
+
const gltfLoader = new GLTFLoader();
|
|
93
|
+
const fbxLoader = new FBXLoader();
|
|
94
|
+
const textureLoader = new THREE.TextureLoader();
|
|
95
|
+
const audioLoader = new THREE.AudioLoader();
|
|
96
|
+
const mtlLoader = new MTLLoader();
|
|
97
|
+
|
|
98
|
+
function storeAssetValue(key, value) {
|
|
99
|
+
if (value && typeof value.then === 'function') {
|
|
100
|
+
const pending = value
|
|
101
|
+
.then(resolved => {
|
|
102
|
+
assetMap.set(key, resolved);
|
|
103
|
+
return resolved;
|
|
104
|
+
})
|
|
105
|
+
.catch(err => {
|
|
106
|
+
console.error(`Failed to load asset "${key}":`, err);
|
|
107
|
+
assetMap.delete(key);
|
|
108
|
+
return null;
|
|
109
|
+
});
|
|
110
|
+
assetMap.set(key, pending);
|
|
111
|
+
} else {
|
|
112
|
+
assetMap.set(key, value);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Scan stylesheets for custom @rules that declare external assets.
|
|
118
|
+
*
|
|
119
|
+
* Syntax:
|
|
120
|
+
* @MyShip {
|
|
121
|
+
* url: "./ship.glb";
|
|
122
|
+
* name: "Spaceship"; // optional, overrides @ identifier
|
|
123
|
+
* }
|
|
124
|
+
*/
|
|
125
|
+
function gatherAssetRules() {
|
|
126
|
+
const ignoreAtRules = new Set([
|
|
127
|
+
'media', 'import', 'supports', 'keyframes', 'font-face', 'charset',
|
|
128
|
+
'namespace', 'page', 'counter-style', 'font-feature-values', 'viewport'
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
for (const sheet of document.styleSheets) {
|
|
132
|
+
let rules;
|
|
133
|
+
try {
|
|
134
|
+
rules = sheet.cssRules;
|
|
135
|
+
} catch {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (const rule of rules) {
|
|
140
|
+
const text = rule.cssText?.trim();
|
|
141
|
+
if (!text) continue;
|
|
142
|
+
|
|
143
|
+
const match = text.match(/^@([A-Za-z0-9_-]+)\s*\{([^}]*)\}/);
|
|
144
|
+
if (!match) continue;
|
|
145
|
+
|
|
146
|
+
const atName = match[1];
|
|
147
|
+
if (ignoreAtRules.has(atName.toLowerCase())) continue;
|
|
148
|
+
|
|
149
|
+
const body = match[2];
|
|
150
|
+
const obj = {};
|
|
151
|
+
body.split(';').forEach(line => {
|
|
152
|
+
const parts = line
|
|
153
|
+
.split(':')
|
|
154
|
+
.map(s => s && s.trim())
|
|
155
|
+
.filter(Boolean);
|
|
156
|
+
if (parts.length >= 2) {
|
|
157
|
+
const key = parts[0].toLowerCase();
|
|
158
|
+
let value = parts[1];
|
|
159
|
+
value = value.replace(/^['"(]+|['")]+$/g, '');
|
|
160
|
+
obj[key] = value;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const url = obj.url;
|
|
165
|
+
if (!url) continue;
|
|
166
|
+
|
|
167
|
+
let name;
|
|
168
|
+
if (obj.name && obj.name.trim()) {
|
|
169
|
+
name = obj.name.trim();
|
|
170
|
+
} else {
|
|
171
|
+
name = atName || (() => {
|
|
172
|
+
const fname = url.split('/').pop() || '';
|
|
173
|
+
const dot = fname.lastIndexOf('.');
|
|
174
|
+
return dot >= 0 ? fname.slice(0, dot) : fname;
|
|
175
|
+
})();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!assetMap.has(name)) {
|
|
179
|
+
storeAssetValue(name, loadAsset(url));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Get or load an asset by name.
|
|
187
|
+
*
|
|
188
|
+
* Built-ins (auto-registered on first use):
|
|
189
|
+
* - cube → BoxGeometry
|
|
190
|
+
* - sphere → SphereGeometry
|
|
191
|
+
* - plane → PlaneGeometry
|
|
192
|
+
* - torus → TorusGeometry
|
|
193
|
+
*
|
|
194
|
+
* @param {string} name
|
|
195
|
+
* @param {string|null} [path=null]
|
|
196
|
+
* @returns {any}
|
|
197
|
+
*/
|
|
198
|
+
export function getAsset(name, path = null) {
|
|
199
|
+
if (assetMap.size === 0) {
|
|
200
|
+
storeAssetValue('cube', new THREE.BoxGeometry());
|
|
201
|
+
storeAssetValue('sphere', new THREE.SphereGeometry());
|
|
202
|
+
storeAssetValue('plane', new THREE.PlaneGeometry());
|
|
203
|
+
storeAssetValue('torus', new THREE.TorusGeometry());
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// read CSS-defined assets
|
|
207
|
+
gatherAssetRules();
|
|
208
|
+
|
|
209
|
+
const key = name;
|
|
210
|
+
if (!assetMap.has(key)) {
|
|
211
|
+
if (!path) {
|
|
212
|
+
console.warn(`Asset "${name}" missing and no path supplied.`);
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
storeAssetValue(key, loadAsset(path));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return assetMap.get(key);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Load a 3D / texture / audio / material asset based on file extension.
|
|
223
|
+
*
|
|
224
|
+
* @param {string} url
|
|
225
|
+
* @returns {Promise<any>|null}
|
|
226
|
+
*/
|
|
227
|
+
export function loadAsset(url) {
|
|
228
|
+
const ext = (url.split('.').pop() || '').toLowerCase();
|
|
229
|
+
switch (ext) {
|
|
230
|
+
case 'gltf':
|
|
231
|
+
case 'glb':
|
|
232
|
+
return new Promise((res, rej) =>
|
|
233
|
+
gltfLoader.load(url, d => res(d.scene || d), null, rej)
|
|
234
|
+
);
|
|
235
|
+
case 'fbx':
|
|
236
|
+
return new Promise((res, rej) =>
|
|
237
|
+
fbxLoader.load(url, res, null, rej)
|
|
238
|
+
);
|
|
239
|
+
case 'png':
|
|
240
|
+
case 'jpg':
|
|
241
|
+
case 'jpeg':
|
|
242
|
+
case 'gif':
|
|
243
|
+
case 'webp':
|
|
244
|
+
return new Promise((res, rej) =>
|
|
245
|
+
textureLoader.load(url, tex => res(tex), undefined, rej)
|
|
246
|
+
);
|
|
247
|
+
case 'mp3':
|
|
248
|
+
case 'wav':
|
|
249
|
+
case 'ogg':
|
|
250
|
+
case 'flac':
|
|
251
|
+
case 'aac':
|
|
252
|
+
return new Promise((res, rej) =>
|
|
253
|
+
audioLoader.load(url, buffer => res(buffer), undefined, rej)
|
|
254
|
+
);
|
|
255
|
+
case 'mtl':
|
|
256
|
+
return new Promise((res, rej) =>
|
|
257
|
+
mtlLoader.load(
|
|
258
|
+
url,
|
|
259
|
+
mtl => {
|
|
260
|
+
mtl.preload();
|
|
261
|
+
res(mtl);
|
|
262
|
+
},
|
|
263
|
+
undefined,
|
|
264
|
+
rej
|
|
265
|
+
)
|
|
266
|
+
);
|
|
267
|
+
case 'json':
|
|
268
|
+
return fetch(url)
|
|
269
|
+
.then(response => response.json())
|
|
270
|
+
.then(json => {
|
|
271
|
+
try {
|
|
272
|
+
const loader = new THREE.MaterialLoader();
|
|
273
|
+
return loader.parse(json);
|
|
274
|
+
} catch (err) {
|
|
275
|
+
console.warn(`MaterialLoader failed to parse ${url}:`, err);
|
|
276
|
+
return json;
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
default:
|
|
280
|
+
console.warn(`No loader for ".${ext}".`);
|
|
281
|
+
return Promise.resolve(null);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Remove an item from an array without preserving order.
|
|
287
|
+
*
|
|
288
|
+
* @param {Array<any>} arry
|
|
289
|
+
* @param {any} item
|
|
290
|
+
*/
|
|
291
|
+
export function fastRemove_arry(arry, item) {
|
|
292
|
+
const index = arry.indexOf(item);
|
|
293
|
+
if (index !== -1) {
|
|
294
|
+
arry[index] = arry[arry.length - 1];
|
|
295
|
+
arry.pop();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Alias for older code.
|
|
300
|
+
export const fastRemoveArray = fastRemove_arry;
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jailedthreejs",
|
|
3
|
+
"version": "0.9.2-beta.0",
|
|
4
|
+
"description": "Dedicated To Willson :D, A small, fast and lightweight Three.js framework.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "M.K.",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"module": "dist/index.js",
|
|
10
|
+
"exports": "./dist/index.js",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"threejs",
|
|
16
|
+
"three-js",
|
|
17
|
+
"webgl",
|
|
18
|
+
"3d",
|
|
19
|
+
"3d-engine",
|
|
20
|
+
"css",
|
|
21
|
+
"css-variables",
|
|
22
|
+
"html",
|
|
23
|
+
"dom",
|
|
24
|
+
"declarative-3d",
|
|
25
|
+
"scene-graph",
|
|
26
|
+
"animation",
|
|
27
|
+
"raycaster",
|
|
28
|
+
"gltf",
|
|
29
|
+
"fbx"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"dev": "vite"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"nodemon": "^3.1.10",
|
|
36
|
+
"vite": "^5.4.21"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"three": "^0.177.0"
|
|
40
|
+
}
|
|
41
|
+
}
|