@jiant/canvable 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 +85 -85
- package/dist/main.d.mts +89 -11
- package/dist/main.d.ts +89 -11
- package/dist/main.js +300 -60
- package/dist/main.mjs +296 -60
- package/package.json +7 -4
package/dist/main.mjs
CHANGED
|
@@ -255,13 +255,14 @@ var Vector2D = class _Vector2D {
|
|
|
255
255
|
}
|
|
256
256
|
};
|
|
257
257
|
|
|
258
|
-
// src/nodes/Node.ts
|
|
258
|
+
// src/nodes/shapes/Node.ts
|
|
259
259
|
import { v4 as uuidv4 } from "uuid";
|
|
260
260
|
var Node = class {
|
|
261
261
|
pos;
|
|
262
262
|
id;
|
|
263
263
|
children = [];
|
|
264
264
|
scene;
|
|
265
|
+
boundingBox;
|
|
265
266
|
constructor(scene, config) {
|
|
266
267
|
this.scene = scene;
|
|
267
268
|
const { id, pos } = config || {};
|
|
@@ -288,25 +289,54 @@ var Node = class {
|
|
|
288
289
|
}
|
|
289
290
|
};
|
|
290
291
|
|
|
291
|
-
// src/nodes/BoundingBox.ts
|
|
292
|
+
// src/nodes/boundingBox/BoundingBox.ts
|
|
292
293
|
var BoundingBox = class extends Node {
|
|
293
294
|
};
|
|
294
295
|
|
|
295
|
-
// src/nodes/
|
|
296
|
-
var
|
|
297
|
-
|
|
298
|
-
constructor(
|
|
299
|
-
super();
|
|
300
|
-
this.
|
|
296
|
+
// src/nodes/boundingBox/SquareBoundingBox.ts
|
|
297
|
+
var SquareBoundingBox = class _SquareBoundingBox extends BoundingBox {
|
|
298
|
+
size;
|
|
299
|
+
constructor(scene, size) {
|
|
300
|
+
super(scene);
|
|
301
|
+
this.size = size || new Vector2D(10, 10);
|
|
301
302
|
}
|
|
302
|
-
|
|
303
|
+
checkCollision(other) {
|
|
304
|
+
if (other instanceof _SquareBoundingBox) {
|
|
305
|
+
const thisPoint = this.scene?.camera.transformCoordinates(new Vector2D(this.pos.x, this.pos.y));
|
|
306
|
+
const otherPoint = this.scene?.camera.transformCoordinates(new Vector2D(other.pos.x, other.pos.y));
|
|
307
|
+
if (!thisPoint || !otherPoint) return { isColliding: false };
|
|
308
|
+
const dx = Math.abs(thisPoint.x - otherPoint.x);
|
|
309
|
+
const dy = Math.abs(thisPoint.y - otherPoint.y);
|
|
310
|
+
const halfWidths = (this.size.x + other.size.x) / 2;
|
|
311
|
+
const halfHeights = (this.size.y + other.size.y) / 2;
|
|
312
|
+
if (dx < halfWidths && dy < halfHeights) {
|
|
313
|
+
const overlapX = halfWidths - dx;
|
|
314
|
+
const overlapY = halfHeights - dy;
|
|
315
|
+
if (overlapX < overlapY) {
|
|
316
|
+
const mtvX = thisPoint.x < otherPoint.x ? -overlapX : overlapX;
|
|
317
|
+
return { isColliding: true, mtv: new Vector2D(mtvX, 0) };
|
|
318
|
+
} else {
|
|
319
|
+
const mtvY = thisPoint.y < otherPoint.y ? -overlapY : overlapY;
|
|
320
|
+
return { isColliding: true, mtv: new Vector2D(0, mtvY) };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (other instanceof CircleBoundingBox) {
|
|
325
|
+
const result = other.checkCollision(this);
|
|
326
|
+
if (result.isColliding && result.mtv) {
|
|
327
|
+
return { isColliding: true, mtv: new Vector2D(-result.mtv.x, -result.mtv.y) };
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return { isColliding: false };
|
|
303
331
|
}
|
|
304
|
-
|
|
305
|
-
|
|
332
|
+
isPointInside(_point) {
|
|
333
|
+
const x_inside = _point.x >= this.pos.x - this.size.x && _point.x <= this.pos.x + this.size.x;
|
|
334
|
+
const y_inside = _point.y >= this.pos.y - this.size.y && _point.y <= this.pos.y + this.size.y;
|
|
335
|
+
return x_inside && y_inside;
|
|
306
336
|
}
|
|
307
337
|
};
|
|
308
338
|
|
|
309
|
-
// src/nodes/CircleBoundingBox.ts
|
|
339
|
+
// src/nodes/boundingBox/CircleBoundingBox.ts
|
|
310
340
|
var CircleBoundingBox = class _CircleBoundingBox extends BoundingBox {
|
|
311
341
|
radius;
|
|
312
342
|
constructor(scene, radius) {
|
|
@@ -315,15 +345,28 @@ var CircleBoundingBox = class _CircleBoundingBox extends BoundingBox {
|
|
|
315
345
|
}
|
|
316
346
|
checkCollision(other) {
|
|
317
347
|
if (other instanceof _CircleBoundingBox) {
|
|
318
|
-
const
|
|
319
|
-
const
|
|
320
|
-
if (!thisPoint || !otherPoint) return false;
|
|
321
|
-
const dx = thisPoint.x - otherPoint.x;
|
|
322
|
-
const dy = thisPoint.y - otherPoint.y;
|
|
348
|
+
const dx = this.pos.x - other.pos.x;
|
|
349
|
+
const dy = this.pos.y - other.pos.y;
|
|
323
350
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
324
|
-
|
|
351
|
+
if (distance < this.radius + other.radius) {
|
|
352
|
+
const overlap = this.radius + other.radius - distance;
|
|
353
|
+
const mtv = distance === 0 ? new Vector2D(overlap, 0) : new Vector2D(dx / distance * overlap, dy / distance * overlap);
|
|
354
|
+
return { isColliding: true, mtv };
|
|
355
|
+
}
|
|
325
356
|
}
|
|
326
|
-
|
|
357
|
+
if (other instanceof SquareBoundingBox) {
|
|
358
|
+
const closestX = Math.max(other.pos.x - other.size.x / 2, Math.min(this.pos.x, other.pos.x + other.size.x / 2));
|
|
359
|
+
const closestY = Math.max(other.pos.y - other.size.y / 2, Math.min(this.pos.y, other.pos.y + other.size.y / 2));
|
|
360
|
+
const dx = this.pos.x - closestX;
|
|
361
|
+
const dy = this.pos.y - closestY;
|
|
362
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
363
|
+
if (distance < this.radius) {
|
|
364
|
+
const overlap = this.radius - distance;
|
|
365
|
+
const mtv = distance === 0 ? new Vector2D(overlap, 0) : new Vector2D(dx / distance * overlap, dy / distance * overlap);
|
|
366
|
+
return { isColliding: true, mtv };
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return { isColliding: false };
|
|
327
370
|
}
|
|
328
371
|
isPointInside(_point) {
|
|
329
372
|
const point = this.scene?.camera.transformCoordinates(_point);
|
|
@@ -335,40 +378,104 @@ var CircleBoundingBox = class _CircleBoundingBox extends BoundingBox {
|
|
|
335
378
|
}
|
|
336
379
|
};
|
|
337
380
|
|
|
338
|
-
// src/nodes/
|
|
339
|
-
var
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
this.
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
381
|
+
// src/nodes/Camera.ts
|
|
382
|
+
var Camera = class extends Node {
|
|
383
|
+
zoom;
|
|
384
|
+
constructor(zoom = 1) {
|
|
385
|
+
super();
|
|
386
|
+
this.zoom = zoom;
|
|
387
|
+
}
|
|
388
|
+
update(deltaTime) {
|
|
389
|
+
}
|
|
390
|
+
transformCoordinates(position) {
|
|
391
|
+
return new Vector2D((position.x - this.pos.x) * this.zoom, (position.y - this.pos.y) * this.zoom);
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// src/nodes/physics/StaticBody.ts
|
|
396
|
+
var StaticBody = class extends Node {
|
|
397
|
+
shape;
|
|
398
|
+
constructor(scene, shape) {
|
|
399
|
+
super(scene, { pos: shape.pos });
|
|
400
|
+
this.shape = shape;
|
|
401
|
+
this.pos = shape.pos;
|
|
402
|
+
}
|
|
403
|
+
update(_dt) {
|
|
404
|
+
if (this.shape.update && typeof this.shape.update === "function") {
|
|
405
|
+
this.shape.update(_dt);
|
|
352
406
|
}
|
|
353
407
|
}
|
|
354
408
|
draw(ctx, selected) {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
409
|
+
if (this.shape.draw) this.shape.draw(ctx, selected);
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// src/nodes/physics/KinematicBody.ts
|
|
414
|
+
var KinematicBody = class _KinematicBody extends Node {
|
|
415
|
+
shape;
|
|
416
|
+
velocity = new Vector2D();
|
|
417
|
+
speed = 1500;
|
|
418
|
+
friction = 0.92;
|
|
419
|
+
maxSpeed = 800;
|
|
420
|
+
isColliding = false;
|
|
421
|
+
constructor(scene, shape, config) {
|
|
422
|
+
super(scene, { pos: shape.pos });
|
|
423
|
+
this.shape = shape;
|
|
424
|
+
if (config?.speed) this.speed = config.speed;
|
|
425
|
+
if (config?.friction) this.friction = config.friction;
|
|
426
|
+
if (config?.maxSpeed) this.maxSpeed = config.maxSpeed;
|
|
427
|
+
}
|
|
428
|
+
applyForce(x, y, dt) {
|
|
429
|
+
const len = Math.sqrt(x * x + y * y);
|
|
430
|
+
if (len > 0) {
|
|
431
|
+
const scale = this.speed * dt / len;
|
|
432
|
+
this.velocity.x += x * scale;
|
|
433
|
+
this.velocity.y += y * scale;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
update(dt) {
|
|
437
|
+
this.velocity.x *= this.friction;
|
|
438
|
+
this.velocity.y *= this.friction;
|
|
439
|
+
const currentSpeed = Math.sqrt(this.velocity.x * this.velocity.x + this.velocity.y * this.velocity.y);
|
|
440
|
+
if (currentSpeed > this.maxSpeed) {
|
|
441
|
+
const scale = this.maxSpeed / currentSpeed;
|
|
442
|
+
this.velocity.x *= scale;
|
|
443
|
+
this.velocity.y *= scale;
|
|
444
|
+
}
|
|
445
|
+
if (Math.abs(this.velocity.x) < 0.1) this.velocity.x = 0;
|
|
446
|
+
if (Math.abs(this.velocity.y) < 0.1) this.velocity.y = 0;
|
|
447
|
+
this.pos.x += this.velocity.x * dt;
|
|
448
|
+
this.pos.y += this.velocity.y * dt;
|
|
449
|
+
this.shape.pos = this.pos;
|
|
450
|
+
if (this.shape.update) this.shape.update(dt);
|
|
451
|
+
this.resolveCollisions();
|
|
452
|
+
}
|
|
453
|
+
resolveCollisions() {
|
|
454
|
+
this.isColliding = false;
|
|
455
|
+
if (!this.shape.boundingBox) return;
|
|
456
|
+
if (!this.scene) return;
|
|
457
|
+
for (const obj of this.scene.children) {
|
|
458
|
+
if (obj === this) continue;
|
|
459
|
+
let otherBBox = null;
|
|
460
|
+
if (obj instanceof StaticBody || obj instanceof _KinematicBody) {
|
|
461
|
+
if (obj.shape.boundingBox) otherBBox = obj.shape.boundingBox;
|
|
462
|
+
} else {
|
|
463
|
+
if (obj.boundingBox) otherBBox = obj.boundingBox;
|
|
464
|
+
}
|
|
465
|
+
if (otherBBox) {
|
|
466
|
+
const result = this.shape.boundingBox.checkCollision(otherBBox);
|
|
467
|
+
if (result.isColliding && result.mtv) {
|
|
468
|
+
this.isColliding = true;
|
|
469
|
+
this.pos.x += result.mtv.x;
|
|
470
|
+
this.pos.y += result.mtv.y;
|
|
471
|
+
this.shape.pos = this.pos;
|
|
472
|
+
if (this.shape.boundingBox) this.shape.boundingBox.pos = this.pos;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
366
475
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
ctx.fill();
|
|
371
|
-
ctx.closePath();
|
|
476
|
+
}
|
|
477
|
+
draw(ctx, selected) {
|
|
478
|
+
if (this.shape.draw) this.shape.draw(ctx, selected);
|
|
372
479
|
}
|
|
373
480
|
};
|
|
374
481
|
|
|
@@ -394,14 +501,14 @@ var InputManager = class extends Node {
|
|
|
394
501
|
this.mousePos = new Vector2D(event.clientX, event.clientY);
|
|
395
502
|
}
|
|
396
503
|
handleKeyDown(event) {
|
|
397
|
-
const key = event.
|
|
504
|
+
const key = event.code;
|
|
398
505
|
if (!this.keyState.get(key)) {
|
|
399
506
|
this.keyState.set(key, true);
|
|
400
507
|
this.keyJustPressed.add(key);
|
|
401
508
|
}
|
|
402
509
|
}
|
|
403
510
|
handleKeyUp(event) {
|
|
404
|
-
const key = event.
|
|
511
|
+
const key = event.code;
|
|
405
512
|
this.keyState.set(key, false);
|
|
406
513
|
this.keyJustPressed.delete(key);
|
|
407
514
|
}
|
|
@@ -440,10 +547,12 @@ var InputManager = class extends Node {
|
|
|
440
547
|
};
|
|
441
548
|
|
|
442
549
|
// src/nodes/Scene.ts
|
|
443
|
-
var
|
|
550
|
+
var Scene = class extends Node {
|
|
444
551
|
camera;
|
|
445
552
|
inputManager;
|
|
446
553
|
ctx;
|
|
554
|
+
animationFrameId = null;
|
|
555
|
+
running = false;
|
|
447
556
|
lastTime = 0;
|
|
448
557
|
totalTime = 0;
|
|
449
558
|
constructor(ctx, opts) {
|
|
@@ -468,7 +577,7 @@ var Scene2 = class extends Node {
|
|
|
468
577
|
canvas.width = width;
|
|
469
578
|
canvas.height = height;
|
|
470
579
|
}
|
|
471
|
-
|
|
580
|
+
updateFrame(deltaTime) {
|
|
472
581
|
this.camera.update(deltaTime);
|
|
473
582
|
this.children.forEach((child) => {
|
|
474
583
|
if (isUpdatable(child)) {
|
|
@@ -476,16 +585,20 @@ var Scene2 = class extends Node {
|
|
|
476
585
|
}
|
|
477
586
|
});
|
|
478
587
|
}
|
|
479
|
-
|
|
480
|
-
ctx.fillStyle = ctx.canvas.style.backgroundColor;
|
|
588
|
+
drawFrame(ctx) {
|
|
589
|
+
ctx.fillStyle = ctx.canvas.style.backgroundColor || "black";
|
|
481
590
|
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
591
|
+
ctx.save();
|
|
592
|
+
ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2);
|
|
482
593
|
this.children.forEach((child) => {
|
|
483
594
|
if (isDrawable(child)) {
|
|
484
595
|
child.draw(ctx);
|
|
485
596
|
}
|
|
486
597
|
});
|
|
598
|
+
ctx.restore();
|
|
487
599
|
}
|
|
488
|
-
|
|
600
|
+
run(callback, targetFPS = 60) {
|
|
601
|
+
this.running = true;
|
|
489
602
|
const frameInterval = 1e3 / targetFPS;
|
|
490
603
|
let lastFrameTime = 0;
|
|
491
604
|
const loop = (currentTime) => {
|
|
@@ -496,8 +609,8 @@ var Scene2 = class extends Node {
|
|
|
496
609
|
this.lastTime = currentTime;
|
|
497
610
|
this.totalTime += deltaTime;
|
|
498
611
|
lastFrameTime = currentTime - elapsed % frameInterval;
|
|
499
|
-
this.
|
|
500
|
-
this.
|
|
612
|
+
this.updateFrame(deltaTime);
|
|
613
|
+
this.drawFrame(this.ctx);
|
|
501
614
|
if (callback) {
|
|
502
615
|
callback(deltaTime, this.totalTime);
|
|
503
616
|
}
|
|
@@ -509,7 +622,14 @@ var Scene2 = class extends Node {
|
|
|
509
622
|
requestAnimationFrame(loop);
|
|
510
623
|
};
|
|
511
624
|
this.lastTime = performance.now();
|
|
512
|
-
requestAnimationFrame(loop);
|
|
625
|
+
this.animationFrameId = requestAnimationFrame(loop);
|
|
626
|
+
}
|
|
627
|
+
stop() {
|
|
628
|
+
if (this.animationFrameId) {
|
|
629
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
630
|
+
this.animationFrameId = null;
|
|
631
|
+
}
|
|
632
|
+
this.running = false;
|
|
513
633
|
}
|
|
514
634
|
};
|
|
515
635
|
function isUpdatable(obj) {
|
|
@@ -519,6 +639,118 @@ function isDrawable(obj) {
|
|
|
519
639
|
return "draw" in obj;
|
|
520
640
|
}
|
|
521
641
|
|
|
642
|
+
// src/nodes/shapes/Circle.ts
|
|
643
|
+
var Circle = class extends Node {
|
|
644
|
+
vel = new Vector2D();
|
|
645
|
+
size = 10;
|
|
646
|
+
friction = 0.1;
|
|
647
|
+
style = {
|
|
648
|
+
fillStyle: "blue"
|
|
649
|
+
};
|
|
650
|
+
constructor(scene, config) {
|
|
651
|
+
super(scene);
|
|
652
|
+
this.vel = config?.vel || new Vector2D();
|
|
653
|
+
this.size = config?.size || 10;
|
|
654
|
+
this.friction = config?.friction || 0.1;
|
|
655
|
+
this.style = { ...this.style, ...config?.style };
|
|
656
|
+
if (config?.startsWithBoundingBox) {
|
|
657
|
+
this.boundingBox = new CircleBoundingBox(scene, this.size);
|
|
658
|
+
this.addObject(this.boundingBox);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
update(_deltaTime) {
|
|
662
|
+
if (this.boundingBox) {
|
|
663
|
+
this.boundingBox.pos = this.pos;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
draw(ctx, selected) {
|
|
667
|
+
const cameraPos = this.scene?.camera.pos || new Vector2D();
|
|
668
|
+
const cameraScale = this.scene?.camera.zoom || 1;
|
|
669
|
+
const relativePos = new Vector2D((this.pos.x - cameraPos.x) * cameraScale, (this.pos.y - cameraPos.y) * cameraScale);
|
|
670
|
+
if (selected) {
|
|
671
|
+
ctx.beginPath();
|
|
672
|
+
ctx.arc(relativePos.x, relativePos.y, this.size + 5, 0, Math.PI * 2);
|
|
673
|
+
ctx.fillStyle = "transparent";
|
|
674
|
+
ctx.lineWidth = 3;
|
|
675
|
+
ctx.strokeStyle = "white";
|
|
676
|
+
ctx.stroke();
|
|
677
|
+
ctx.closePath();
|
|
678
|
+
}
|
|
679
|
+
ctx.beginPath();
|
|
680
|
+
ctx.arc(relativePos.x, relativePos.y, this.size, 0, Math.PI * 2);
|
|
681
|
+
ctx.fillStyle = this.style.fillStyle || "blue";
|
|
682
|
+
ctx.fill();
|
|
683
|
+
if (this.style.strokeStyle) {
|
|
684
|
+
ctx.strokeStyle = this.style.strokeStyle;
|
|
685
|
+
ctx.lineWidth = this.style.lineWidth || 1;
|
|
686
|
+
ctx.stroke();
|
|
687
|
+
}
|
|
688
|
+
ctx.closePath();
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
// src/nodes/shapes/Square.ts
|
|
693
|
+
var Square = class extends Node {
|
|
694
|
+
vel = new Vector2D();
|
|
695
|
+
size;
|
|
696
|
+
friction = 0.1;
|
|
697
|
+
style = {
|
|
698
|
+
fillStyle: "orange"
|
|
699
|
+
};
|
|
700
|
+
constructor(scene, config) {
|
|
701
|
+
super(scene);
|
|
702
|
+
this.vel = config?.vel || new Vector2D();
|
|
703
|
+
this.size = config?.size || new Vector2D(10, 10);
|
|
704
|
+
this.friction = config?.friction || 0.1;
|
|
705
|
+
this.style = { ...this.style, ...config?.style };
|
|
706
|
+
if (config?.startsWithBoundingBox) {
|
|
707
|
+
this.boundingBox = new SquareBoundingBox(scene, this.size);
|
|
708
|
+
this.addObject(this.boundingBox);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
update(_deltaTime) {
|
|
712
|
+
if (this.boundingBox) {
|
|
713
|
+
this.boundingBox.pos = this.pos;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
draw(ctx, selected) {
|
|
717
|
+
const cameraPos = this.scene?.camera.pos || new Vector2D();
|
|
718
|
+
const cameraScale = this.scene?.camera.zoom || 1;
|
|
719
|
+
const relativePos = new Vector2D(
|
|
720
|
+
(this.pos.x - cameraPos.x) * cameraScale,
|
|
721
|
+
(this.pos.y - cameraPos.y) * cameraScale
|
|
722
|
+
);
|
|
723
|
+
const scaledSize = new Vector2D(this.size.x * cameraScale, this.size.y * cameraScale);
|
|
724
|
+
if (selected) {
|
|
725
|
+
ctx.strokeStyle = "white";
|
|
726
|
+
ctx.lineWidth = 3;
|
|
727
|
+
ctx.strokeRect(
|
|
728
|
+
relativePos.x - scaledSize.x / 2 - 5,
|
|
729
|
+
relativePos.y - scaledSize.y / 2 - 5,
|
|
730
|
+
scaledSize.x + 10,
|
|
731
|
+
scaledSize.y + 10
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
ctx.fillStyle = this.style.fillStyle || "orange";
|
|
735
|
+
ctx.fillRect(
|
|
736
|
+
relativePos.x - scaledSize.x / 2,
|
|
737
|
+
relativePos.y - scaledSize.y / 2,
|
|
738
|
+
scaledSize.x,
|
|
739
|
+
scaledSize.y
|
|
740
|
+
);
|
|
741
|
+
if (this.style.strokeStyle) {
|
|
742
|
+
ctx.strokeStyle = this.style.strokeStyle;
|
|
743
|
+
ctx.lineWidth = this.style.lineWidth || 1;
|
|
744
|
+
ctx.strokeRect(
|
|
745
|
+
relativePos.x - scaledSize.x / 2,
|
|
746
|
+
relativePos.y - scaledSize.y / 2,
|
|
747
|
+
scaledSize.x,
|
|
748
|
+
scaledSize.y
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
|
|
522
754
|
// src/main.ts
|
|
523
755
|
function getCanvas(id) {
|
|
524
756
|
const canvas = document.getElementById(id);
|
|
@@ -532,8 +764,12 @@ export {
|
|
|
532
764
|
Camera,
|
|
533
765
|
Circle,
|
|
534
766
|
CircleBoundingBox,
|
|
767
|
+
KinematicBody,
|
|
535
768
|
Node,
|
|
536
|
-
|
|
769
|
+
Scene,
|
|
770
|
+
Square,
|
|
771
|
+
SquareBoundingBox,
|
|
772
|
+
StaticBody,
|
|
537
773
|
TWO_PI,
|
|
538
774
|
Vector2D,
|
|
539
775
|
getCanvas
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jiant/canvable",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "A tool for building canvas apps",
|
|
5
5
|
"main": "./dist/main.js",
|
|
6
6
|
"module": "./dist/main.mjs",
|
|
@@ -12,14 +12,17 @@
|
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsup",
|
|
15
|
-
"
|
|
15
|
+
"watch": "tsup --watch",
|
|
16
|
+
"dev": "vite"
|
|
16
17
|
},
|
|
17
18
|
"dependencies": {
|
|
18
19
|
"uuid": "^11.0.3"
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|
|
22
|
+
"@types/node": "^25.2.0",
|
|
23
|
+
"tsup": "^8.3.5",
|
|
21
24
|
"typescript": "^5.7.2",
|
|
22
|
-
"
|
|
25
|
+
"vite": "^7.3.1"
|
|
23
26
|
},
|
|
24
27
|
"keywords": [
|
|
25
28
|
"canvas",
|
|
@@ -34,4 +37,4 @@
|
|
|
34
37
|
"publishConfig": {
|
|
35
38
|
"access": "public"
|
|
36
39
|
}
|
|
37
|
-
}
|
|
40
|
+
}
|