Index: test/ward-sky.test.js
===================================================================
--- test/ward-sky.test.js	(revision 084b046d930ee79f779d73d05b08e90d00fd684f)
+++ test/ward-sky.test.js	(revision 3866994fe8be998ed18b62cee35531e7d013b18d)
@@ -9,5 +9,5 @@
 import assert from 'node:assert/strict';
 
-const { orbitPlacement, nearestFace } = await import('../src/assets/js/ward-sky.js');
+const { orbitPlacement, nearestFace, SkyRenderer } = await import('../src/assets/js/ward-sky.js');
 
 const r = (s) => Math.hypot(s.x, s.y);
@@ -68,2 +68,33 @@
   assert.equal(at(1.5), 1);
 });
+
+test('zoomen houdt het punt onder je vingers op zijn plek', () => {
+  // De kern van pinch-to-zoom: de wereld onder het midden tussen je vingers
+  // mag NIET wegschuiven. We rekenen _zoomAround na zonder een echt canvas,
+  // door de renderer een minimale staat te geven.
+  // We hebben geen DOM, dus bouwen een kaal object met alleen wat _zoomAround
+  // aanraakt en lenen de methode.
+  const fake = { w: 400, h: 400, scale: 1, panX: 0, panY: 0,
+    _clampScale: SkyRenderer.prototype._clampScale };
+  const zoom = SkyRenderer.prototype._zoomAround;
+
+  // Welk wereldpunt ligt nu onder (px,py)?
+  const worldUnder = (o, px, py) => ({
+    x: (px - o.w / 2 - o.panX) / o.scale,
+    y: (py - o.h / 2 - o.panY) / o.scale,
+  });
+  const px = 300, py = 120;
+  const before = worldUnder(fake, px, py);
+  zoom.call(fake, px, py, 1.6);   // inzoomen om dat punt
+  const after = worldUnder(fake, px, py);
+
+  assert.ok(Math.abs(before.x - after.x) < 1e-6, 'x schoof weg onder de vingers');
+  assert.ok(Math.abs(before.y - after.y) < 1e-6, 'y schoof weg onder de vingers');
+  assert.ok(fake.scale > 1, 'er is niet ingezoomd');
+});
+
+test('de zoom blijft binnen zijn grenzen', () => {
+  const clamp = SkyRenderer.prototype._clampScale;
+  assert.equal(clamp(10), 2.5);    // niet eindeloos in
+  assert.equal(clamp(0.01), 0.2);  // niet eindeloos uit
+});
