@playcraft/build 0.0.13 → 0.0.15

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.
Files changed (82) hide show
  1. package/dist/analyzers/scene-asset-collector.js +99 -9
  2. package/dist/base-builder.d.ts +15 -78
  3. package/dist/base-builder.js +34 -741
  4. package/dist/engines/engine-detector.d.ts +38 -0
  5. package/dist/engines/engine-detector.js +201 -0
  6. package/dist/engines/generic-adapter.d.ts +71 -0
  7. package/dist/engines/generic-adapter.js +378 -0
  8. package/dist/engines/index.d.ts +7 -0
  9. package/dist/engines/index.js +7 -0
  10. package/dist/engines/playcanvas-adapter.d.ts +85 -0
  11. package/dist/engines/playcanvas-adapter.js +813 -0
  12. package/dist/generators/config-generator.js +59 -1
  13. package/dist/index.d.ts +4 -0
  14. package/dist/index.js +4 -0
  15. package/dist/loaders/playcraft-loader.js +240 -5
  16. package/dist/platforms/adikteev.d.ts +1 -1
  17. package/dist/platforms/adikteev.js +30 -36
  18. package/dist/platforms/applovin.d.ts +1 -1
  19. package/dist/platforms/applovin.js +31 -36
  20. package/dist/platforms/base.d.ts +27 -5
  21. package/dist/platforms/base.js +79 -181
  22. package/dist/platforms/bigo.d.ts +1 -1
  23. package/dist/platforms/bigo.js +28 -28
  24. package/dist/platforms/facebook.d.ts +1 -1
  25. package/dist/platforms/facebook.js +21 -10
  26. package/dist/platforms/google.d.ts +1 -1
  27. package/dist/platforms/google.js +28 -21
  28. package/dist/platforms/index.d.ts +1 -0
  29. package/dist/platforms/index.js +4 -0
  30. package/dist/platforms/inmobi.d.ts +1 -1
  31. package/dist/platforms/inmobi.js +27 -34
  32. package/dist/platforms/ironsource.d.ts +1 -1
  33. package/dist/platforms/ironsource.js +37 -40
  34. package/dist/platforms/liftoff.d.ts +1 -1
  35. package/dist/platforms/liftoff.js +22 -30
  36. package/dist/platforms/mintegral.d.ts +10 -0
  37. package/dist/platforms/mintegral.js +65 -0
  38. package/dist/platforms/moloco.d.ts +1 -1
  39. package/dist/platforms/moloco.js +18 -20
  40. package/dist/platforms/playcraft.d.ts +1 -1
  41. package/dist/platforms/playcraft.js +2 -2
  42. package/dist/platforms/remerge.d.ts +1 -1
  43. package/dist/platforms/remerge.js +19 -20
  44. package/dist/platforms/snapchat.d.ts +1 -1
  45. package/dist/platforms/snapchat.js +32 -26
  46. package/dist/platforms/tiktok.d.ts +1 -1
  47. package/dist/platforms/tiktok.js +28 -24
  48. package/dist/platforms/unity.d.ts +1 -1
  49. package/dist/platforms/unity.js +30 -36
  50. package/dist/playable-builder.d.ts +1 -0
  51. package/dist/playable-builder.js +16 -2
  52. package/dist/types.d.ts +113 -1
  53. package/dist/types.js +77 -1
  54. package/dist/utils/ammo-detector.d.ts +9 -0
  55. package/dist/utils/ammo-detector.js +76 -0
  56. package/dist/utils/build-mode-detector.js +2 -0
  57. package/dist/utils/minify.d.ts +32 -0
  58. package/dist/utils/minify.js +82 -0
  59. package/dist/utils/obfuscate.d.ts +42 -0
  60. package/dist/utils/obfuscate.js +216 -0
  61. package/dist/vite/config-builder-generic.d.ts +70 -0
  62. package/dist/vite/config-builder-generic.js +251 -0
  63. package/dist/vite/config-builder.d.ts +8 -0
  64. package/dist/vite/config-builder.js +53 -16
  65. package/dist/vite/platform-configs.js +29 -1
  66. package/dist/vite/plugin-compress-js.d.ts +21 -0
  67. package/dist/vite/plugin-compress-js.js +213 -0
  68. package/dist/vite/plugin-esm-html-generator.js +5 -1
  69. package/dist/vite/plugin-obfuscate.d.ts +22 -0
  70. package/dist/vite/plugin-obfuscate.js +52 -0
  71. package/dist/vite/plugin-platform.d.ts +5 -0
  72. package/dist/vite/plugin-platform.js +499 -35
  73. package/dist/vite/plugin-playcanvas.js +21 -68
  74. package/dist/vite/plugin-source-builder.js +102 -21
  75. package/dist/vite-builder.d.ts +25 -7
  76. package/dist/vite-builder.js +141 -52
  77. package/package.json +4 -2
  78. package/physics/cannon-rigidbody-adapter.js +243 -22
  79. package/templates/__loading__.js +0 -12
  80. package/templates/index.esm.mjs +0 -11
  81. package/templates/patches/playcraft-cta-adapter.js +129 -31
  82. package/templates/patches/scene-physics-defaults.js +49 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcraft/build",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -39,7 +39,8 @@
39
39
  "lightningcss": "^1.31.1",
40
40
  "mime-types": "^2.1.35",
41
41
  "rollup-plugin-visualizer": "^6.0.5",
42
- "sharp": "^0.33.5",
42
+ "sharp": "^0.34.5",
43
+ "javascript-obfuscator": "^5.3.0",
43
44
  "terser": "^5.46.0",
44
45
  "vite": "^6.4.1",
45
46
  "vite-plugin-singlefile": "^2.3.0"
@@ -48,6 +49,7 @@
48
49
  "@types/archiver": "^6.0.4",
49
50
  "@types/mime-types": "^2.1.4",
50
51
  "@types/node": "^22.19.8",
52
+ "fflate": "^0.8.2",
51
53
  "typescript": "^5.9.3"
52
54
  }
53
55
  }
@@ -22,6 +22,7 @@
22
22
  // Store references
23
23
  var cannonWorld = null;
24
24
  var rigidBodyMap = []; // Array of { entity, body } pairs
25
+ var triggerBodyMap = []; // Array of { entity, body } pairs for trigger volumes
25
26
  var initialized = false;
26
27
 
27
28
  /**
@@ -44,6 +45,20 @@
44
45
  var bodyA = event.bodyA;
45
46
  var bodyB = event.bodyB;
46
47
 
48
+ // Check if either body is a trigger
49
+ if (bodyA.isTrigger || bodyB.isTrigger) {
50
+ var triggerBody = bodyA.isTrigger ? bodyA : bodyB;
51
+ var otherBody = bodyA.isTrigger ? bodyB : bodyA;
52
+
53
+ if (triggerBody.entity && otherBody.entity) {
54
+ // Fire triggerenter on the trigger entity's collision component
55
+ if (triggerBody.entity.collision) {
56
+ triggerBody.entity.collision.fire('triggerenter', otherBody.entity);
57
+ }
58
+ }
59
+ return;
60
+ }
61
+
47
62
  if (bodyA.entity && bodyB.entity) {
48
63
  bodyA.entity.fire('collisionstart', { other: bodyB.entity });
49
64
  bodyB.entity.fire('collisionstart', { other: bodyA.entity });
@@ -54,6 +69,19 @@
54
69
  var bodyA = event.bodyA;
55
70
  var bodyB = event.bodyB;
56
71
 
72
+ // Check if either body is a trigger
73
+ if (bodyA.isTrigger || bodyB.isTrigger) {
74
+ var triggerBody = bodyA.isTrigger ? bodyA : bodyB;
75
+ var otherBody = bodyA.isTrigger ? bodyB : bodyA;
76
+
77
+ if (triggerBody.entity && otherBody.entity) {
78
+ if (triggerBody.entity.collision) {
79
+ triggerBody.entity.collision.fire('triggerleave', otherBody.entity);
80
+ }
81
+ }
82
+ return;
83
+ }
84
+
57
85
  if (bodyA.entity && bodyB.entity) {
58
86
  bodyA.entity.fire('collisionend', { other: bodyB.entity });
59
87
  bodyB.entity.fire('collisionend', { other: bodyA.entity });
@@ -61,10 +89,110 @@
61
89
  });
62
90
 
63
91
  cannonWorld = world;
92
+
93
+ // Set default contact material
94
+ world.defaultContactMaterial.friction = 0.5;
95
+ world.defaultContactMaterial.restitution = 0.3;
96
+
64
97
  console.log('[Cannon Adapter] Cannon world created with gravity:', gravity);
65
98
  return world;
66
99
  }
67
100
 
101
+ /**
102
+ * Create a collision shape for mesh type by extracting AABB from the render asset.
103
+ */
104
+ function createMeshShape(entity, onShapeReady) {
105
+ var collision = entity.collision;
106
+ var renderAssetId = collision.renderAsset;
107
+
108
+ if (renderAssetId) {
109
+ var app = pc.Application.getApplication();
110
+ if (app) {
111
+ var asset = app.assets.get(renderAssetId);
112
+
113
+ if (asset && !asset.resource) {
114
+ // Asset exists but not yet loaded — defer shape creation
115
+ asset.ready(function() {
116
+ var shape = extractShapeFromAsset(asset, entity);
117
+ if (shape && onShapeReady) {
118
+ onShapeReady(shape);
119
+ }
120
+ });
121
+ app.assets.load(asset);
122
+ return null;
123
+ }
124
+
125
+ if (asset && asset.resource) {
126
+ return extractShapeFromAsset(asset, entity);
127
+ }
128
+ }
129
+ }
130
+
131
+ // Fallback: try entity's own render/model component
132
+ return extractShapeFromMeshInstances(entity);
133
+ }
134
+
135
+ /**
136
+ * Extract a box shape from an asset's mesh instances AABB.
137
+ */
138
+ function extractShapeFromAsset(asset, entity) {
139
+ var meshInstances = null;
140
+
141
+ if (asset.resource.meshInstances) {
142
+ meshInstances = asset.resource.meshInstances;
143
+ } else if (asset.resource.renders && asset.resource.renders.length > 0) {
144
+ meshInstances = asset.resource.renders[0].meshInstances;
145
+ }
146
+
147
+ if (meshInstances && meshInstances.length > 0) {
148
+ return buildBoxFromMeshInstances(meshInstances, entity);
149
+ }
150
+ return null;
151
+ }
152
+
153
+ /**
154
+ * Extract a box shape from entity's own render/model mesh instances.
155
+ */
156
+ function extractShapeFromMeshInstances(entity) {
157
+ var mi = null;
158
+ if (entity.render && entity.render.meshInstances) {
159
+ mi = entity.render.meshInstances;
160
+ } else if (entity.model && entity.model.meshInstances) {
161
+ mi = entity.model.meshInstances;
162
+ }
163
+ if (mi && mi.length > 0) {
164
+ return buildBoxFromMeshInstances(mi, entity);
165
+ }
166
+ return null;
167
+ }
168
+
169
+ /**
170
+ * Build a CANNON.Box from merged AABB of mesh instances.
171
+ */
172
+ function buildBoxFromMeshInstances(meshInstances, entity) {
173
+ var mergedAabb = null;
174
+ for (var j = 0; j < meshInstances.length; j++) {
175
+ var instanceAabb = meshInstances[j].aabb;
176
+ if (instanceAabb) {
177
+ if (!mergedAabb) {
178
+ mergedAabb = instanceAabb.clone();
179
+ } else {
180
+ mergedAabb.add(instanceAabb);
181
+ }
182
+ }
183
+ }
184
+ if (mergedAabb) {
185
+ var he = mergedAabb.halfExtents;
186
+ var scale = entity.getLocalScale();
187
+ return new CANNON.Box(new CANNON.Vec3(
188
+ he.x * scale.x,
189
+ he.y * scale.y,
190
+ he.z * scale.z
191
+ ));
192
+ }
193
+ return null;
194
+ }
195
+
68
196
  /**
69
197
  * Create Cannon shape from PlayCanvas collision component
70
198
  */
@@ -99,9 +227,31 @@
99
227
  collision.height,
100
228
  8
101
229
  );
230
+ } else if (type === 'mesh') {
231
+ // Pass a deferred callback — if the asset isn't loaded yet, the shape
232
+ // will be swapped in once the asset finishes loading.
233
+ var deferredEntity = entity;
234
+ shape = createMeshShape(entity, function(loadedShape) {
235
+ // Find the body that was created for this entity and swap the shape
236
+ for (var idx = 0; idx < rigidBodyMap.length; idx++) {
237
+ if (rigidBodyMap[idx].entity === deferredEntity) {
238
+ var body = rigidBodyMap[idx].body;
239
+ // Remove old shapes and add the loaded one
240
+ while (body.shapes.length > 0) {
241
+ body.removeShape(body.shapes[0]);
242
+ }
243
+ body.addShape(loadedShape);
244
+ console.log('[Cannon Adapter] Deferred mesh shape loaded for:', deferredEntity.name);
245
+ break;
246
+ }
247
+ }
248
+ });
249
+ if (!shape) {
250
+ console.warn('[Cannon Adapter] Mesh collision: asset not ready, using temporary default box for:', entity.name);
251
+ shape = new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5));
252
+ }
102
253
  } else {
103
254
  console.warn('[Cannon Adapter] Unsupported collision type:', type);
104
- // Default to box
105
255
  shape = new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5));
106
256
  }
107
257
 
@@ -132,30 +282,39 @@
132
282
  mass = 0;
133
283
  }
134
284
 
285
+ var bodyMaterial = new CANNON.Material();
286
+ if (rb.friction !== undefined) bodyMaterial.friction = rb.friction;
287
+ if (rb.restitution !== undefined) bodyMaterial.restitution = rb.restitution;
288
+
135
289
  var body = new CANNON.Body({
136
290
  mass: mass,
137
291
  position: new CANNON.Vec3(pos.x, pos.y, pos.z),
138
292
  quaternion: new CANNON.Quaternion(rot.x, rot.y, rot.z, rot.w),
139
- shape: shape
293
+ shape: shape,
294
+ material: bodyMaterial,
295
+ linearDamping: rb.linearDamping || 0,
296
+ angularDamping: rb.angularDamping || 0
140
297
  });
141
298
 
142
299
  if (bodyType === 'kinematic') {
143
300
  body.type = CANNON.Body.KINEMATIC;
144
301
  }
145
302
 
146
- // Store entity reference
147
- body.entity = entity;
148
-
149
- // Store friction and restitution
150
- if (rb.friction !== undefined) {
151
- body.material = body.material || new CANNON.Material();
152
- body.material.friction = rb.friction;
303
+ // Apply linearFactor and angularFactor
304
+ if (rb.linearFactor) {
305
+ var lf = rb.linearFactor;
306
+ if (Array.isArray(lf)) body.linearFactor.set(lf[0], lf[1], lf[2]);
307
+ else if (lf.x !== undefined) body.linearFactor.set(lf.x, lf.y, lf.z);
153
308
  }
154
- if (rb.restitution !== undefined) {
155
- body.material = body.material || new CANNON.Material();
156
- body.material.restitution = rb.restitution;
309
+ if (rb.angularFactor) {
310
+ var af = rb.angularFactor;
311
+ if (Array.isArray(af)) body.angularFactor.set(af[0], af[1], af[2]);
312
+ else if (af.x !== undefined) body.angularFactor.set(af.x, af.y, af.z);
157
313
  }
158
314
 
315
+ // Store entity reference
316
+ body.entity = entity;
317
+
159
318
  // Add to world
160
319
  world.addBody(body);
161
320
  rigidBodyMap.push({ entity: entity, body: body });
@@ -164,6 +323,40 @@
164
323
  return body;
165
324
  }
166
325
 
326
+ /**
327
+ * Create a trigger body for entities with collision but no rigidbody
328
+ * In PlayCanvas, entities with collision but no rigidbody act as triggers
329
+ */
330
+ function createTriggerBody(entity, world) {
331
+ if (!entity.collision || entity.rigidbody) {
332
+ return null;
333
+ }
334
+
335
+ var shape = createCannonShape(entity);
336
+ if (!shape) return null;
337
+
338
+ var pos = entity.getPosition();
339
+ var rot = entity.getRotation();
340
+
341
+ var body = new CANNON.Body({
342
+ mass: 0,
343
+ position: new CANNON.Vec3(pos.x, pos.y, pos.z),
344
+ quaternion: new CANNON.Quaternion(rot.x, rot.y, rot.z, rot.w),
345
+ shape: shape,
346
+ collisionResponse: false // Trigger bodies don't produce collision response
347
+ });
348
+
349
+ body.entity = entity;
350
+ body.isTrigger = true;
351
+
352
+ world.addBody(body);
353
+ triggerBodyMap.push({ entity: entity, body: body });
354
+ rigidBodyMap.push({ entity: entity, body: body });
355
+
356
+ console.log('[Cannon Adapter] Created trigger body for entity:', entity.name);
357
+ return body;
358
+ }
359
+
167
360
  /**
168
361
  * Create compatibility layer for rigidbody API
169
362
  */
@@ -180,10 +373,30 @@
180
373
  }
181
374
 
182
375
  // Override rigidbody methods to use Cannon.js
183
- rb.applyForce = function(x, y, z, px, py, pz) {
184
- var force = new CANNON.Vec3(x, y, z);
185
- if (px !== undefined && py !== undefined && pz !== undefined) {
186
- var point = new CANNON.Vec3(px, py, pz);
376
+ // applyForce supports two calling conventions:
377
+ // 1. applyForce(forceVec3, [pointVec3]) — two Vec3 objects
378
+ // 2. applyForce(fx, fy, fz, [px, py, pz]) — six numbers
379
+ rb.applyForce = function() {
380
+ var force, point;
381
+ var a = arguments;
382
+
383
+ if (a.length >= 1 && typeof a[0] === 'object' && a[0] !== null && a[0].x !== undefined) {
384
+ // Vec3 calling convention
385
+ force = new CANNON.Vec3(a[0].x, a[0].y, a[0].z);
386
+ if (a.length >= 2 && typeof a[1] === 'object' && a[1] !== null && a[1].x !== undefined) {
387
+ point = new CANNON.Vec3(a[1].x, a[1].y, a[1].z);
388
+ }
389
+ } else if (a.length >= 3) {
390
+ // Number calling convention
391
+ force = new CANNON.Vec3(a[0], a[1], a[2]);
392
+ if (a.length >= 6) {
393
+ point = new CANNON.Vec3(a[3], a[4], a[5]);
394
+ }
395
+ } else {
396
+ return;
397
+ }
398
+
399
+ if (point) {
187
400
  cannonBody.applyForce(force, point);
188
401
  } else {
189
402
  cannonBody.applyForce(force);
@@ -197,7 +410,7 @@
197
410
  } else {
198
411
  cannonImpulse = new CANNON.Vec3(impulse, relativePoint || 0, arguments[2] || 0);
199
412
  }
200
-
413
+
201
414
  if (relativePoint && relativePoint.x !== undefined) {
202
415
  var point = new CANNON.Vec3(relativePoint.x, relativePoint.y, relativePoint.z);
203
416
  cannonBody.applyImpulse(cannonImpulse, point);
@@ -311,15 +524,23 @@
311
524
 
312
525
  var world = initCannonWorld(app);
313
526
  var count = 0;
527
+ var triggerCount = 0;
314
528
 
315
- // Find all entities with rigidbody component
529
+ // Find all entities with rigidbody component or trigger collision
316
530
  function processEntity(entity) {
317
531
  if (entity.rigidbody && entity.collision) {
532
+ // Entity with both rigidbody and collision = physics body
318
533
  var body = createCannonBody(entity, world);
319
534
  if (body) {
320
535
  wrapRigidbodyAPI(entity, body);
321
536
  count++;
322
537
  }
538
+ } else if (entity.collision && !entity.rigidbody) {
539
+ // Entity with collision but no rigidbody = trigger volume
540
+ var triggerBody = createTriggerBody(entity, world);
541
+ if (triggerBody) {
542
+ triggerCount++;
543
+ }
323
544
  }
324
545
 
325
546
  // Process children
@@ -331,7 +552,7 @@
331
552
 
332
553
  processEntity(app.root);
333
554
 
334
- console.log('[Cannon Adapter] Initialized', count, 'rigidbodies');
555
+ console.log('[Cannon Adapter] Initialized', count, 'rigidbodies and', triggerCount, 'triggers');
335
556
  initialized = true;
336
557
 
337
558
  // Hook into update loop
@@ -355,11 +576,11 @@
355
576
  function waitForApp() {
356
577
  if (typeof pc !== 'undefined' && pc.Application && pc.Application.getApplication) {
357
578
  var app = pc.Application.getApplication();
358
- if (app) {
359
- // Wait for first frame to ensure all scripts are loaded
579
+ if (app && app.root && app.root.children.length > 0) {
580
+ // Scene is loaded. Wait for assets (mesh colliders need render assets loaded)
360
581
  setTimeout(function() {
361
582
  initializeRigidbodies(app);
362
- }, 100);
583
+ }, 200);
363
584
  return;
364
585
  }
365
586
  }
@@ -21,10 +21,6 @@ pc.script.createLoadingScreen((app) => {
21
21
  left: calc(50% - 132px);
22
22
  }
23
23
 
24
- #application-splash img {
25
- width: 100%;
26
- }
27
-
28
24
  #progress-bar-container {
29
25
  margin: 20px auto 0 auto;
30
26
  height: 2px;
@@ -59,14 +55,6 @@ pc.script.createLoadingScreen((app) => {
59
55
  const splash = document.createElement('div');
60
56
  splash.id = 'application-splash';
61
57
  wrapper.appendChild(splash);
62
- splash.style.display = 'none';
63
-
64
- const logo = document.createElement('img');
65
- logo.src = `${ASSET_PREFIX}logo.png`;
66
- splash.appendChild(logo);
67
- logo.onload = () => {
68
- splash.style.display = 'block';
69
- };
70
58
 
71
59
  const container = document.createElement('div');
72
60
  container.id = 'progress-bar-container';
@@ -426,10 +426,6 @@ pc.script.createLoadingScreen(app => {
426
426
  left: calc(50% - 132px);
427
427
  }
428
428
 
429
- #application-splash img {
430
- width: 100%;
431
- }
432
-
433
429
  #progress-bar-container {
434
430
  margin: 20px auto 0 auto;
435
431
  height: 2px;
@@ -462,13 +458,6 @@ pc.script.createLoadingScreen(app => {
462
458
  const splash = document.createElement('div');
463
459
  splash.id = 'application-splash';
464
460
  wrapper.appendChild(splash);
465
- splash.style.display = 'none';
466
- const logo = document.createElement('img');
467
- logo.src = `${ASSET_PREFIX}logo.png`;
468
- splash.appendChild(logo);
469
- logo.onload = () => {
470
- splash.style.display = 'block';
471
- };
472
461
  const container = document.createElement('div');
473
462
  container.id = 'progress-bar-container';
474
463
  splash.appendChild(container);