{"_id":"@abd2oo1/math-engine","_rev":"5-0dc0f8ed2f33996227565e1bcc0d9c2a","name":"@abd2oo1/math-engine","dist-tags":{"latest":"1.1.4"},"versions":{"1.0.0":{"name":"@abd2oo1/math-engine","version":"1.0.0","author":"","license":"ISC","_id":"@abd2oo1/math-engine@1.0.0","maintainers":[{"name":"abd2oo1","email":"abdullah.r.rhaif@gmail.com"}],"dist":{"shasum":"25ba793c25d571a24300699cee5c54bc2e3c9cef","tarball":"https://registry.npmjs.org/@abd2oo1/math-engine/-/math-engine-1.0.0.tgz","fileCount":21,"integrity":"sha512-NI3wZyV1XHIAN18bsYZqOyy6+ATlr1a0YzqepWIw5yLh7Lzn9oi+t0Q71FXnn8n5+F3uhNFpFc9cgjvwKsxX4A==","signatures":[{"sig":"MEUCIQCbk8wL5ODo76NKG0uH8SIlHsZ6Riz85WwJl4j4docXyAIgPGiOh36P9GQR9O1sjhGPGekpSRRiSStKaEJmnJn54BA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37481},"main":"dist/index.js","type":"commonjs","types":"dist/index.d.ts","scripts":{"dev":"tsc --watch","build":"tsc"},"_npmUser":{"name":"abd2oo1","email":"abdullah.r.rhaif@gmail.com"},"_npmVersion":"11.3.0","description":"","directories":{},"_nodeVersion":"24.1.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/math-engine_1.0.0_1773482236119_0.22450454192118907","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@abd2oo1/math-engine","version":"1.0.2","author":"","license":"ISC","_id":"@abd2oo1/math-engine@1.0.2","maintainers":[{"name":"abd2oo1","email":"abdullah.r.rhaif@gmail.com"}],"dist":{"shasum":"233617c8a3ed0aca8a286ea5b71979bf6d025fbd","tarball":"https://registry.npmjs.org/@abd2oo1/math-engine/-/math-engine-1.0.2.tgz","fileCount":22,"integrity":"sha512-0eYUFPOxy4mwT1uqMOx2NeyfrxC18XvaFpz/HCNmhUo12G0AzICrRKySPoC42iv2Ifba32teQiMmEMfadyGzcQ==","signatures":[{"sig":"MEUCIHBj6NZtSRZT0eQZ0y2g+xeLrQ0O5F6871OHPsOU3e/mAiEA7TXyEoU5FfwFPwgxlPaTo+eOGOk+gU9l1vtfYTGoadk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51456},"main":"dist/index.js","type":"commonjs","types":"dist/index.d.ts","scripts":{"dev":"tsc --watch","build":"tsc"},"_npmUser":{"name":"abd2oo1","email":"abdullah.r.rhaif@gmail.com"},"_npmVersion":"11.3.0","description":"A lightweight 2D math engine for spatial applications such as seating chart libraries, canvas editors, and game engines. Built with TypeScript, zero dependencies.","directories":{},"_nodeVersion":"24.1.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/math-engine_1.0.2_1773482689776_0.7648930960748663","host":"s3://npm-registry-packages-npm-production"}},"1.1.4":{"name":"@abd2oo1/math-engine","version":"1.1.4","main":"dist/index.js","types":"dist/index.d.ts","description":"A lightweight 2D math engine for spatial applications such as seating chart libraries, canvas editors, and game engines. Built with TypeScript, zero dependencies.","license":"ISC","author":"","type":"commonjs","scripts":{"build":"tsc","dev":"tsc --watch"},"devDependencies":{"typescript":"^5.9.3"},"dependencies":{"@abd2oo1/math-engine":"^1.0.2"},"_id":"@abd2oo1/math-engine@1.1.4","_nodeVersion":"24.1.0","_npmVersion":"11.3.0","dist":{"integrity":"sha512-Wryq7B3Fr7cbWkm5+pb1CcfnrNdMetZssM4TgGRJLmFsFQhPAICdcFUsrrMTppKFah2vPW8ISQfrsOkHY5taQA==","shasum":"a69d323a3a00f6239d7c2c8e6ad60c3354e5175a","tarball":"https://registry.npmjs.org/@abd2oo1/math-engine/-/math-engine-1.1.4.tgz","fileCount":22,"unpackedSize":51300,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDplS5rS3vpB3ROJnXwb7pQdByzLJ3yUIOA6zKaGUJryAiEA0jyFiantrzkaMqQNQ/Y1eipshPq0eJ89HTw4IyscPjc="}]},"_npmUser":{"name":"abd2oo1","email":"abdullah.r.rhaif@gmail.com"},"directories":{},"maintainers":[{"name":"abd2oo1","email":"abdullah.r.rhaif@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/math-engine_1.1.4_1774086030596_0.6394286474734803"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-14T09:57:16.018Z","modified":"2026-03-21T09:40:30.843Z","1.0.1":"2026-03-14T09:56:12.539Z","1.0.0":"2026-03-14T09:57:16.273Z","1.0.2":"2026-03-14T10:04:49.917Z","1.1.4":"2026-03-21T09:40:30.739Z"},"license":"ISC","description":"A lightweight 2D math engine for spatial applications such as seating chart libraries, canvas editors, and game engines. Built with TypeScript, zero dependencies.","maintainers":[{"name":"abd2oo1","email":"abdullah.r.rhaif@gmail.com"}],"readme":"# math-engine-2d\n\nA lightweight 2D math engine for spatial applications such as seating chart libraries, canvas editors, and game engines. Built with TypeScript, zero dependencies.\n\n---\n\n## Installation\n\n```bash\nnpm install math-engine-2d\n```\n\n---\n\n## Usage\n\n```js\nimport math from 'math-engine-2d'\n\n// use any module\nmath.vector.add({ x: 1, y: 2 }, { x: 3, y: 4 }) // { x: 4, y: 6 }\nmath.circle.pointInsideCircle({ x: 1, y: 1 }, { x: 0, y: 0, r: 5 }) // true\n```\n\n---\n\n## Modules\n\n- [vector](#vector)\n- [circle](#circle)\n- [rectangle](#rectangle)\n- [bound](#bound)\n- [intersect](#intersect)\n- [trigonometry](#trigonometry)\n- [angle](#angle)\n- [utils](#utils)\n\n---\n\n## vector\n\n2D vector operations. All functions take `{ x, y }` objects and return new vectors without mutating the input.\n\n### `add(a, b)`\nAdds two vectors together.\n```js\nmath.vector.add({ x: 1, y: 2 }, { x: 3, y: 4 })\n// { x: 4, y: 6 }\n```\n\n### `subtract(a, b)`\nSubtracts vector `b` from vector `a`.\n```js\nmath.vector.subtract({ x: 5, y: 5 }, { x: 2, y: 3 })\n// { x: 3, y: 2 }\n```\n\n### `scale(v, t)`\nScales a vector by a scalar value.\n```js\nmath.vector.scale({ x: 2, y: 3 }, 2)\n// { x: 4, y: 6 }\n```\n\n### `dot(a, b)`\nReturns the dot product of two vectors. Used for finding the angle between two rows or projecting a point onto a line.\n```js\nmath.vector.dot({ x: 1, y: 0 }, { x: 0, y: 1 })\n// 0\n```\n\n### `magnitude(v)`\nReturns the length of a vector.\n```js\nmath.vector.magnitude({ x: 3, y: 4 })\n// 5\n```\n\n### `normalize(v)`\nReturns a unit vector (length = 1) in the same direction.\n```js\nmath.vector.normalize({ x: 3, y: 4 })\n// { x: 0.6, y: 0.8 }\n```\n\n### `lerp(a, b, t)`\nLinearly interpolates between two vectors by `t` (0 to 1). Used for placing seats evenly along a straight row.\n```js\nmath.vector.lerp({ x: 0, y: 0 }, { x: 100, y: 0 }, 0.5)\n// { x: 50, y: 0 }\n```\n\n### `distance(a, b)`\nReturns the distance between two points.\n```js\nmath.vector.distance({ x: 0, y: 0 }, { x: 3, y: 4 })\n// 5\n```\n\n### `perpendicular(v)`\nReturns a vector perpendicular to the given vector. Used for row orientation and normal directions.\n```js\nmath.vector.perpendicular({ x: 1, y: 0 })\n// { x: 0, y: 1 }\n```\n\n---\n\n## circle\n\nOperations on circles `{ x, y, r }` where `x, y` is the center and `r` is the radius.\n\n### `pointInsideCircle(point, circle)`\nChecks if a point is inside a circle. Used for seat hit testing.\n```js\nmath.circle.pointInsideCircle({ x: 1, y: 1 }, { x: 0, y: 0, r: 5 })\n// true\n```\n\n### `pointOutsideCircle(point, circle)`\nChecks if a point is outside a circle.\n```js\nmath.circle.pointOutsideCircle({ x: 10, y: 10 }, { x: 0, y: 0, r: 5 })\n// true\n```\n\n### `pointOnCircle(point, circle)`\nChecks if a point lies exactly on the circle boundary, with floating point tolerance.\n```js\nmath.circle.pointOnCircle({ x: 5, y: 0 }, { x: 0, y: 0, r: 5 })\n// true\n```\n\n### `distanceBetweenCircles(a, b)`\nReturns the distance between two circle centers.\n```js\nmath.circle.distanceBetweenCircles({ x: 0, y: 0, r: 5 }, { x: 10, y: 0, r: 5 })\n// 10\n```\n\n### `circlesOverlap(a, b)`\nChecks if two circles overlap. Used for detecting if two seats are too close.\n```js\nmath.circle.circlesOverlap({ x: 0, y: 0, r: 5 }, { x: 8, y: 0, r: 5 })\n// true\n```\n\n### `pointOnCircleEdge(circle, angle)`\nReturns the point on the circle edge at a given angle in radians. Used for placing seats on a curved row.\n```js\nmath.circle.pointOnCircleEdge({ x: 0, y: 0, r: 100 }, 0)\n// { x: 100, y: 0 }\n\nmath.circle.pointOnCircleEdge({ x: 0, y: 0, r: 100 }, Math.PI / 2)\n// { x: 0, y: 100 }\n```\n\n### `circleBounds(circle)`\nReturns the bounding box of a circle. Used for culling — skipping seats that are off screen.\n```js\nmath.circle.circleBounds({ x: 50, y: 50, r: 20 })\n// { left: 30, top: 30, right: 70, bottom: 70 }\n```\n\n---\n\n## rectangle\n\nOperations on rectangles `{ x, y, width, height }` where `x, y` is the top-left corner.\n\n### `pointInsideRectangle(point, rect)`\nChecks if a point is inside a rectangle. Used for drag selection.\n```js\nmath.rectangle.pointInsideRectangle({ x: 50, y: 50 }, { x: 0, y: 0, width: 100, height: 100 })\n// true\n```\n\n### `rectangleContainsRectangle(a, b)`\nChecks if rectangle `a` fully contains rectangle `b`. Used for checking if a section is inside a pricing zone.\n```js\nmath.rectangle.rectangleContainsRectangle(\n  { x: 0, y: 0, width: 200, height: 200 },\n  { x: 50, y: 50, width: 50, height: 50 }\n)\n// true\n```\n\n### `rectangleIntersectsCircle(rect, circle)`\nChecks if a rectangle overlaps or touches a circle. Used for drag selection — does the box touch this seat?\n```js\nmath.rectangle.rectangleIntersectsCircle(\n  { x: 0, y: 0, width: 100, height: 100 },\n  { x: 110, y: 50, r: 20 }\n)\n// true\n```\n\n### `rectangleCenter(rect)`\nReturns the center point of a rectangle. Used for rotating a section around its center.\n```js\nmath.rectangle.rectangleCenter({ x: 0, y: 0, width: 100, height: 100 })\n// { x: 50, y: 50 }\n```\n\n### `rectangleBounds(rect)`\nReturns the bounding box of a rectangle.\n```js\nmath.rectangle.rectangleBounds({ x: 10, y: 20, width: 100, height: 50 })\n// { left: 10, top: 20, right: 110, bottom: 70 }\n```\n\n---\n\n## bound\n\nAxis-Aligned Bounding Box (AABB) operations. All bounds use `{ left, top, right, bottom }`.\n\n### `createBounds(x, y, width, height)`\nCreates a bounding box from position and size.\n```js\nmath.bound.createBounds(10, 20, 100, 50)\n// { left: 10, top: 20, right: 110, bottom: 70 }\n```\n\n### `pointInBounds(point, bounds)`\nChecks if a point is inside a bounding box. Used for drag selection.\n```js\nmath.bound.pointInBounds({ x: 50, y: 50 }, { left: 0, top: 0, right: 100, bottom: 100 })\n// true\n```\n\n### `boundsIntersect(a, b)`\nChecks if two bounding boxes overlap. Used for section collision detection.\n```js\nmath.bound.boundsIntersect(\n  { left: 0, top: 0, right: 100, bottom: 100 },\n  { left: 50, top: 50, right: 150, bottom: 150 }\n)\n// true\n```\n\n### `expandBounds(bounds, padding)`\nExpands a bounding box by a padding value on all sides.\n```js\nmath.bound.expandBounds({ left: 10, top: 10, right: 90, bottom: 90 }, 10)\n// { left: 0, top: 0, right: 100, bottom: 100 }\n```\n\n### `mergeBounds(a, b)`\nMerges two bounding boxes into one that contains both. Used for wrapping an entire section.\n```js\nmath.bound.mergeBounds(\n  { left: 0, top: 0, right: 50, bottom: 50 },\n  { left: 50, top: 50, right: 100, bottom: 100 }\n)\n// { left: 0, top: 0, right: 100, bottom: 100 }\n```\n\n### `boundsCenter(bounds)`\nReturns the center point of a bounding box.\n```js\nmath.bound.boundsCenter({ left: 0, top: 0, right: 100, bottom: 100 })\n// { x: 50, y: 50 }\n```\n\n### `boundsSize(bounds)`\nReturns the width and height of a bounding box.\n```js\nmath.bound.boundsSize({ left: 0, top: 0, right: 100, bottom: 50 })\n// { width: 100, height: 50 }\n```\n\n### `moveBounds(bounds, dx, dy)`\nMoves a bounding box by `dx` and `dy`.\n```js\nmath.bound.moveBounds({ left: 0, top: 0, right: 100, bottom: 100 }, 50, 50)\n// { left: 50, top: 50, right: 150, bottom: 150 }\n```\n\n### `selectionBounds(point1, point2)`\nCreates a bounding box from two points. Used for drag selection on canvas.\n```js\nmath.bound.selectionBounds({ x: 20, y: 80 }, { x: 80, y: 20 })\n// { left: 20, top: 20, right: 80, bottom: 80 }\n```\n\n### `boundsContainsBounds(a, b)`\nChecks if bounding box `a` fully contains bounding box `b`.\n```js\nmath.bound.boundsContainsBounds(\n  { left: 0, top: 0, right: 200, bottom: 200 },\n  { left: 50, top: 50, right: 100, bottom: 100 }\n)\n// true\n```\n\n### `boundsFromPoints(points)`\nComputes a bounding box that wraps all given points. Used for wrapping a row of seats.\n```js\nmath.bound.boundsFromPoints([\n  { x: 10, y: 20 },\n  { x: 80, y: 5 },\n  { x: 50, y: 90 }\n])\n// { left: 10, top: 5, right: 80, bottom: 90 }\n```\n\n---\n\n## intersect\n\nIntersection tests between shapes.\n\n### `pointInRect(point, bounds)`\nChecks if a point is inside a bounding box.\n```js\nmath.intersect.pointInRect({ x: 50, y: 50 }, { left: 0, top: 0, right: 100, bottom: 100 })\n// true\n```\n\n### `rectIntersect(a, b)`\nChecks if two bounding boxes overlap.\n```js\nmath.intersect.rectIntersect(\n  { left: 0, top: 0, right: 100, bottom: 100 },\n  { left: 80, top: 80, right: 200, bottom: 200 }\n)\n// true\n```\n\n### `lineIntersect(a, b, c, d)`\nChecks if two line segments intersect. Used for detecting if two row lines cross.\n```js\nmath.intersect.lineIntersect(\n  { x: 0, y: 0 }, { x: 100, y: 100 },\n  { x: 100, y: 0 }, { x: 0,   y: 100 }\n)\n// true\n```\n\n### `circleIntersect(a, b)`\nChecks if two circles overlap. Used for detecting if two seats are too close.\n```js\nmath.intersect.circleIntersect(\n  { x: 0, y: 0, r: 10 },\n  { x: 15, y: 0, r: 10 }\n)\n// true\n```\n\n### `pointInCircle(point, circle)`\nChecks if a point is inside a circle. Used for seat hit testing.\n```js\nmath.intersect.pointInCircle({ x: 3, y: 3 }, { x: 0, y: 0, r: 10 })\n// true\n```\n\n### `circleIntersectRect(circle, bounds)`\nChecks if a circle overlaps or touches a rectangle. Used for partial seat selection.\n```js\nmath.intersect.circleIntersectRect(\n  { x: 105, y: 50, r: 10 },\n  { left: 0, top: 0, right: 100, bottom: 100 }\n)\n// true\n```\n\n### `pointToSegmentDistance(point, a, b)`\nReturns the shortest distance from a point to a line segment. Used for snapping a seat to a row line.\n```js\nmath.intersect.pointToSegmentDistance(\n  { x: 50, y: 50 },\n  { x: 0,  y: 0  },\n  { x: 100, y: 0 }\n)\n// 50\n```\n\n### `pointInPolygon(point, polygon)`\nChecks if a point is inside a polygon using ray casting. Used for pricing zones.\n```js\nconst zone = [\n  { x: 0,   y: 0   },\n  { x: 100, y: 0   },\n  { x: 100, y: 100 },\n  { x: 0,   y: 100 }\n]\nmath.intersect.pointInPolygon({ x: 50, y: 50 }, zone)\n// true\n```\n\n---\n\n## trigonometry\n\nTrigonometry utilities for angles, arcs, and rotations. Angles are in radians unless stated otherwise.\n\n### `degToRad(deg)`\nConverts degrees to radians.\n```js\nmath.trigonometry.degToRad(180)\n// 3.14159...\n```\n\n### `radToDeg(rad)`\nConverts radians to degrees.\n```js\nmath.trigonometry.radToDeg(Math.PI)\n// 180\n```\n\n### `pointOnCircle(center, radius, angle)`\nReturns the point on a circle at a given angle. Used for placing seats on a curved row.\n```js\nmath.trigonometry.pointOnCircle({ x: 0, y: 0 }, 100, 0)\n// { x: 100, y: 0 }\n```\n\n### `angleBetweenTwoPoints(point1, point2)`\nReturns the angle between two points in radians using `atan2`.\n```js\nmath.trigonometry.angleBetweenTwoPoints({ x: 0, y: 0 }, { x: 100, y: 0 })\n// 0\n```\n\n### `rotatePoint(point, origin, angle)`\nRotates a point around an origin by a given angle. Used for rotating entire sections.\n```js\nmath.trigonometry.rotatePoint(\n  { x: 100, y: 0 },\n  { cx: 0, cy: 0 },\n  Math.PI / 2\n)\n// { x: 0, y: 100 }\n```\n\n### `distanceBetweenTwoPoints(point1, point2)`\nReturns the distance between two points.\n```js\nmath.trigonometry.distanceBetweenTwoPoints({ x: 0, y: 0 }, { x: 3, y: 4 })\n// 5\n```\n\n### `normalizeAngle(angle)`\nKeeps an angle within the range `[0, 2π]`. Used to prevent angle overflow when looping around arcs.\n```js\nmath.trigonometry.normalizeAngle(7)\n// 0.716...\n```\n\n### `arcAngleStep(seatWidth, radius)`\nReturns the angle step needed to space seats evenly on an arc. Used for curved row layout.\n```js\nmath.trigonometry.arcAngleStep(30, 200)\n// 0.15\n```\n\n### `angleBetweenTwoVectors(a, b)`\nReturns the angle between two vectors in radians. Used for finding row orientation.\n```js\nmath.trigonometry.angleBetweenTwoVectors({ x: 1, y: 0 }, { x: 0, y: 1 })\n// 1.5707... (90°)\n```\n\n---\n\n## angle\n\nAdditional angle utilities.\n\n### `degreesToRadians(deg)`\nConverts degrees to radians.\n```js\nmath.angle.degreesToRadians(90)\n// 1.5707...\n```\n\n### `radiansToDegrees(rad)`\nConverts radians to degrees.\n```js\nmath.angle.radiansToDegrees(Math.PI)\n// 180\n```\n\n### `arcAngleStep(seatWidth, radius)`\nReturns the angle step for even seat spacing on a curved row.\n```js\nmath.angle.arcAngleStep(30, 200)\n// 0.15\n```\n\n### `angleBetweenTwoAngles(a, b)`\nReturns the shortest angular distance between two angles.\n```js\nmath.angle.angleBetweenTwoAngles(0.1, 5.9)\n// -0.483...\n```\n\n### `rotateApointAroundAnotherPoint(origin, point, angle)`\nRotates a point around an origin point by a given angle.\n```js\nmath.angle.rotateApointAroundAnotherPoint(\n  { x: 0, y: 0 },\n  { x: 100, y: 0 },\n  Math.PI / 2\n)\n// { x: 0, y: 100 }\n```\n\n---\n\n## utils\n\nGeneral utility functions.\n\n### `clamp(value, min, max)`\nClamps a value between a minimum and maximum. Returns `min` if below, `max` if above, otherwise the value itself.\n```js\nmath.utils.clamp(150, 0, 100)  // 100\nmath.utils.clamp(-10, 0, 100)  // 0\nmath.utils.clamp(50,  0, 100)  // 50\n```\n\n### `lrep(start, end, percentage)`\nLinearly interpolates between two numbers by a percentage (0 to 1).\n```js\nmath.utils.lrep(0, 100, 0.5)\n// 50\n```\n\n### `lrepBetweenTwoPoints(startPoint, endPoint, percentage)`\nLinearly interpolates between two 2D points by a percentage (0 to 1).\n```js\nmath.utils.lrepBetweenTwoPoints({ x: 0, y: 0 }, { x: 100, y: 100 }, 0.5)\n// { x: 50, y: 50 }\n```\n\n---\n\n## Example — Curved Row Layout\n\n```js\nimport math from 'math-engine-2d'\n\nconst center = { x: 300, y: 300 }\nconst radius = 200\nconst seatWidth = 30\nconst totalSeats = 10\n\nconst step = math.trigonometry.arcAngleStep(seatWidth, radius)\n\nconst seats = []\nfor (let i = 0; i < totalSeats; i++) {\n  const angle = i * step\n  const position = math.trigonometry.pointOnCircle(center, radius, angle)\n  seats.push(position)\n}\n```\n\n---\n\n## Example — Seat Hit Testing\n\n```js\nimport math from 'math-engine-2d'\n\nconst seat = { x: 100, y: 100, r: 15 }\nconst mouseClick = { x: 105, y: 108 }\n\nif (math.circle.pointInsideCircle(mouseClick, seat)) {\n  console.log('seat selected')\n}\n```\n\n---\n\n## Example — Drag Selection\n\n```js\nimport math from 'math-engine-2d'\n\nconst selectionStart = { x: 50,  y: 50  }\nconst selectionEnd   = { x: 200, y: 200 }\nconst box = math.bound.selectionBounds(selectionStart, selectionEnd)\n\nconst seats = [\n  { x: 100, y: 100, r: 15 },\n  { x: 300, y: 300, r: 15 },\n]\n\nconst selected = seats.filter(seat =>\n  math.intersect.circleIntersectRect(seat, box)\n)\n```\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md"}