@zakkster/lite-tools 2.0.14 → 2.0.16

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 (3) hide show
  1. package/LiteEngine.js +59 -46
  2. package/README.md +2 -0
  3. package/package.json +1 -1
package/LiteEngine.js CHANGED
@@ -1031,7 +1031,11 @@ export const Recipes = {
1031
1031
  const ctx = canvas.getContext('2d');
1032
1032
  const rng = new Random(seed);
1033
1033
  seedNoise(seed);
1034
- const cam = new CinematicCamera({smoothing: 0.08, deadzone: 40});
1034
+ const w = canvas.width || 800, h = canvas.height || 600;
1035
+ const cam = new CinematicCamera(w, h, w * 4, h * 4, seed);
1036
+ cam.lerpSpeed = 5.0;
1037
+ cam.deadzoneX = 40;
1038
+ cam.deadzoneY = 40;
1035
1039
  const gradient = new Gradient([
1036
1040
  {l: 0.2, c: 0.15, h: 220}, // deep water
1037
1041
  {l: 0.4, c: 0.2, h: 200}, // shallow
@@ -1040,12 +1044,12 @@ export const Recipes = {
1040
1044
  {l: 0.65, c: 0.08, h: 60}, // mountain
1041
1045
  {l: 0.95, c: 0.02, h: 0}, // snow
1042
1046
  ]);
1043
- let target = {x: 0, y: 0};
1047
+ const _colorOut = {l: 0, c: 0, h: 0};
1048
+ let target = {x: w * 2, y: h * 2};
1044
1049
 
1045
1050
  function render(dt) {
1046
- cam.follow(target.x, target.y, dt);
1047
- const {x: camX, y: camY} = cam.getPosition();
1048
- const w = canvas.width, h = canvas.height;
1051
+ cam.update(dt, target.x, target.y);
1052
+ const camX = cam.pos[0], camY = cam.pos[1];
1049
1053
  const cols = Math.ceil(w / cellSize) + 2;
1050
1054
  const rows = Math.ceil(h / cellSize) + 2;
1051
1055
  const offX = Math.floor(camX / cellSize);
@@ -1056,8 +1060,8 @@ export const Recipes = {
1056
1060
  const wx = (offX + c) * scale;
1057
1061
  const wy = (offY + r) * scale;
1058
1062
  const n = fbm2(wx, wy, 5, 2.0, 0.5) * 0.5 + 0.5;
1059
- const color = gradient.at(clamp(n, 0, 1));
1060
- ctx.fillStyle = toCssOklch(color);
1063
+ gradient.at(clamp(n, 0, 1), _colorOut);
1064
+ ctx.fillStyle = toCssOklch(_colorOut);
1061
1065
  ctx.fillRect((c - (camX / cellSize - offX)) * cellSize, (r - (camY / cellSize - offY)) * cellSize, cellSize + 1, cellSize + 1);
1062
1066
  }
1063
1067
  }
@@ -1072,6 +1076,8 @@ export const Recipes = {
1072
1076
  seedNoise(s);
1073
1077
  },
1074
1078
  destroy() {
1079
+ cam.destroy();
1080
+ gradient.destroy();
1075
1081
  },
1076
1082
  };
1077
1083
  },
@@ -1084,7 +1090,7 @@ export const Recipes = {
1084
1090
  const {width = 32, height = 32, seed = Date.now()} = options;
1085
1091
  const rng = new Random(seed);
1086
1092
  const grid = new Uint8Array(width * height); // 0=wall, 1=floor
1087
- const spatial = new SpatialGrid(width * 4, height * 4, 32);
1093
+ const spatial = new SpatialGrid(width * 4, height * 4, 32, 1000);
1088
1094
 
1089
1095
  // Simple noise-based dungeon
1090
1096
  for (let y = 0; y < height; y++) {
@@ -1210,7 +1216,8 @@ export const Recipes = {
1210
1216
  const ctx = canvas.getContext('2d');
1211
1217
  const rng = new Random(seed);
1212
1218
  const w = canvas.width, h = canvas.height;
1213
- const spatial = new SpatialGrid(w, h, 64);
1219
+ const spatial = new SpatialGrid(w, h, 64, count);
1220
+ const _queryBuf = new Int32Array(64);
1214
1221
  const agents = [];
1215
1222
 
1216
1223
  for (let i = 0; i < count; i++) {
@@ -1223,28 +1230,32 @@ export const Recipes = {
1223
1230
 
1224
1231
  function update(dt) {
1225
1232
  spatial.clear();
1226
- for (const a of agents) spatial.insert(a, a.x, a.y, 4, 4);
1233
+ for (const a of agents) spatial.insert(a.id, a.x, a.y);
1227
1234
 
1228
1235
  for (const a of agents) {
1229
- const neighbors = spatial.query(a.x - 60, a.y - 60, 120, 120).filter(n => n.id !== a.id);
1230
- if (neighbors.length > 0) {
1231
- let sx = 0, sy = 0, ax = 0, ay = 0, cx = 0, cy = 0;
1232
- for (const n of neighbors) {
1233
- const dx = a.x - n.x, dy = a.y - n.y;
1234
- const d = Math.sqrt(dx * dx + dy * dy) || 1;
1235
- if (d < 25) {
1236
- sx += dx / d;
1237
- sy += dy / d;
1238
- }
1239
- ax += n.vx;
1240
- ay += n.vy;
1241
- cx += n.x;
1242
- cy += n.y;
1236
+ const n = spatial.queryRadius(a.x, a.y, 60, _queryBuf, true);
1237
+ let sx = 0, sy = 0, ax = 0, ay = 0, cx = 0, cy = 0, nc = 0;
1238
+ for (let j = 0; j < n; j++) {
1239
+ const nId = _queryBuf[j];
1240
+ if (nId === a.id) continue;
1241
+ const nb = agents[nId];
1242
+ nc++;
1243
+ const dx = a.x - nb.x, dy = a.y - nb.y;
1244
+ const d = Math.sqrt(dx * dx + dy * dy) || 1;
1245
+ if (d < 25) {
1246
+ sx += dx / d;
1247
+ sy += dy / d;
1243
1248
  }
1244
- ax /= neighbors.length;
1245
- ay /= neighbors.length;
1246
- cx /= neighbors.length;
1247
- cy /= neighbors.length;
1249
+ ax += nb.vx;
1250
+ ay += nb.vy;
1251
+ cx += nb.x;
1252
+ cy += nb.y;
1253
+ }
1254
+ if (nc > 0) {
1255
+ ax /= nc;
1256
+ ay /= nc;
1257
+ cx /= nc;
1258
+ cy /= nc;
1248
1259
  a.vx += (sx * 2 + (ax - a.vx) * 0.05 + (cx - a.x) * 0.01) * dt;
1249
1260
  a.vy += (sy * 2 + (ay - a.vy) * 0.05 + (cy - a.y) * 0.01) * dt;
1250
1261
  }
@@ -1281,7 +1292,7 @@ export const Recipes = {
1281
1292
 
1282
1293
  return {
1283
1294
  agents, update, destroy() {
1284
- spatial.clear();
1295
+ spatial.destroy();
1285
1296
  agents.length = 0;
1286
1297
  }
1287
1298
  };
@@ -1299,7 +1310,6 @@ export const Recipes = {
1299
1310
  }, destroy() {
1300
1311
  }
1301
1312
  };
1302
- const gesture = new GestureTracker(el);
1303
1313
  let currentIndex = 0, offsetX = 0;
1304
1314
  const slideWidth = el.clientWidth || 300;
1305
1315
 
@@ -1309,7 +1319,7 @@ export const Recipes = {
1309
1319
  const startX = offsetX;
1310
1320
  const tl = createTimeline();
1311
1321
  tl.add({
1312
- duration: 400, onUpdate(t) {
1322
+ delay: 0, duration: 400, onUpdate(t) {
1313
1323
  offsetX = startX + (targetX - startX) * easeOutCubic(t);
1314
1324
  renderSlides();
1315
1325
  }
@@ -1324,15 +1334,16 @@ export const Recipes = {
1324
1334
  }
1325
1335
  }
1326
1336
 
1327
- gesture.on('panEnd', (e) => {
1328
- if (e.velocityX < -0.3 || e.deltaX < -slideWidth * 0.3) goTo(currentIndex + 1);
1329
- else if (e.velocityX > 0.3 || e.deltaX > slideWidth * 0.3) goTo(currentIndex - 1);
1330
- else goTo(currentIndex);
1331
- });
1332
-
1333
- gesture.on('pan', (e) => {
1334
- offsetX = -currentIndex * slideWidth + e.deltaX;
1335
- renderSlides();
1337
+ const gesture = GestureTracker(el, {
1338
+ onPanMove(e) {
1339
+ offsetX = -currentIndex * slideWidth + e.dx;
1340
+ renderSlides();
1341
+ },
1342
+ onPanEnd(e) {
1343
+ if (e.vx < -300 || e.dx < -slideWidth * 0.3) goTo(currentIndex + 1);
1344
+ else if (e.vx > 300 || e.dx > slideWidth * 0.3) goTo(currentIndex - 1);
1345
+ else goTo(currentIndex);
1346
+ },
1336
1347
  });
1337
1348
 
1338
1349
  renderSlides();
@@ -1395,24 +1406,25 @@ export const Recipes = {
1395
1406
  * Composes: lite-sparks + lite-fireworks + lite-camera
1396
1407
  */
1397
1408
  sparkImpact(canvas, options = {}) {
1398
- const {maxSparks = 5000, maxFireworks = 3000, shakeIntensity = 8} = options;
1409
+ const {maxSparks = 5000, maxFireworks = 3000, shakeIntensity = 0.6} = options;
1399
1410
  const ctx = canvas.getContext('2d');
1400
1411
  const sparks = new SparkEngine(maxSparks);
1401
1412
  const fireworks = new FireworksEngine(maxFireworks);
1402
- const cam = new CinematicCamera({smoothing: 0.05});
1403
1413
  let w = canvas.width, h = canvas.height;
1414
+ const cam = new CinematicCamera(w, h, w, h, 42);
1415
+ cam.lerpSpeed = 20.0;
1416
+ cam.shakeMaxOffset = 12;
1404
1417
 
1405
1418
  function explodeAt(x, y) {
1406
1419
  sparks.burst(x, y, 80, 0, Math.PI * 2, 200, 800, 0.3, 1.0);
1407
1420
  fireworks.explode(x, y, Math.floor(Math.random() * fireworks.colors.length));
1408
- cam.shake(shakeIntensity, 0.3);
1421
+ cam.addTrauma(shakeIntensity);
1409
1422
  }
1410
1423
 
1411
1424
  function update(dt) {
1412
- cam.update(dt);
1413
- const {x: offX, y: offY} = cam.getOffset();
1425
+ cam.update(dt, w * 0.5, h * 0.5);
1414
1426
  ctx.save();
1415
- ctx.translate(offX, offY);
1427
+ cam.apply(ctx);
1416
1428
  fireworks.updateAndDraw(ctx, dt, w, h);
1417
1429
  sparks.updateAndDraw(ctx, dt, w, h);
1418
1430
  ctx.restore();
@@ -1422,6 +1434,7 @@ export const Recipes = {
1422
1434
  explodeAt, update, sparks, fireworks, cam, destroy() {
1423
1435
  sparks.destroy();
1424
1436
  fireworks.destroy();
1437
+ cam.destroy();
1425
1438
  }
1426
1439
  };
1427
1440
  },
package/README.md CHANGED
@@ -13,6 +13,8 @@ The standard library for high-performance web presentation.
13
13
 
14
14
  **[→ Live Recipes Gallery Demo](https://codepen.io/Zahari-Shinikchiev/full/qEarjVG)**
15
15
 
16
+ **[→ Live Recipes Gallery Demo v2](https://cdpn.io/pen/debug/LERQdMR)**
17
+
16
18
  ## Why LiteTools?
17
19
 
18
20
  | Feature | LiteTools | lodash | GSAP | Framer Motion | p5.js |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zakkster/lite-tools",
3
3
  "author": "Zahary Shinikchiev <shinikchiev@yahoo.com>",
4
- "version": "2.0.14",
4
+ "version": "2.0.16",
5
5
  "sideEffects": false,
6
6
  "description": "The standard library for high-performance web presentation — 45+ micro-libraries, 24 recipes, zero-GC, deterministic, tree-shakeable.",
7
7
  "type": "module",