@trap_stevo/zonetide
v0.0.0
Published
A next-generation spatial intelligence and real-time zone-tracking engine engineered for modern simulations, immersive worlds, and high-performance systems. Unlocks dynamic entity evaluation, reactive zone logic, and composable spatial behaviors with supp
Maintainers
Readme
🧭 @trap_stevo/zonetide
A next-generation spatial intelligence and real-time zone-tracking engine engineered for modern simulations, immersive worlds, and high-performance systems.
Unlocks dynamic entity evaluation, reactive zone logic, and composable spatial behaviors with support for offline reasoning, composite zones, and custom shape registries — ideal for games, procedural content, autonomous agents, and geographic systems requiring spatial awareness and control.
🚀 Features
- 🧠 Zone-Aware Tracking – Track entities through complex spatial environments
- 🧩 Composable Zones – Define
circle,box,polygon,union,intersection, anddifferencezones - 🔁 Reusable Shape Registry – Define reusable, parameterized shapes for fast zone creation
- 🔔 Event-Driven Evaluation – React to
enter,exit,stay, andviolationevents - 🔄 Dynamic Zone Management – Create, modify, and resolve zones at runtime
- 🔍 Precomputed Evaluation – Check if a point lies in one or more zones (even without tracking entities)
- 🧰 Storage Hooks – Plug in storage handlers for persistence or audit logging
- ⚙️ Default Zone Loader – Automatically preload zones with custom strategies
📦 API Overview
Initialization
const zone = new ZoneTide(config?);Zone Management
| Method | Description |
|---------------------------------|-------------------------------------------------|
| createZone(zoneData) | Create a new zone |
| createAndSetZone(id, config) | Build and set a zone using a config |
| setZone(id, zone) | Manually assign a zone |
| getZone(id) | Get raw zone definition |
| getResolvedZone(id) | Return fully resolved zone with alias logic |
| removeZone(id) | Delete a zone |
| listZones() | List all defined zones |
Spatial Evaluation
| Method | Description |
|----------------------------------------------|---------------------------------------------------|
| evaluate(entityId, zoneId, pos) | Evaluate if entity is in zone |
| isInsideZone(pos, zoneID) | Returns true if coordinates are in zone |
| getZonesContainingPosition(pos, options) | Get zones that contain a point |
Tracker / Core Access
| Method | Description |
|---------------------|------------------------------------------|
| getTracker() | Access tracker instance |
| getZonalCore() | Access the raw state store |
Storage Hooks
| Method | Description |
|----------------------------|------------------------------------------|
| setStorageHandler(fn) | Set async handler for zone storage ops |
| injectDefaultZones(fn) | Load zones dynamically on startup |
🛠 Developer Utilities
| Utility | Description |
|----------------------------------|------------------------------------------|
| ZoneTide.zone() | Fluent zone builder |
| ZoneTide.createWithDefaults() | Create a preloaded instance |
📦 Installation
npm install @trap_stevo/zonetide🔧 Example Usage
const { ZoneTide } = require("@trap_stevo/zonetide");
const zone = new ZoneTide();
zone.setShapeRegistry({
"spawn-area" : { shape : "circle", center : { x : 0, y : 0 }, radius : 75 },
"fort-box" : { shape : "box", x : 50, y : 50, width : 100, height : 100 }
});
const restrictedZone = ZoneTide.zone()
.id("restricted-fort")
.shape("fort-box")
.type("restricted")
.rule("allowEntry", false)
.build();
await zone.createZone(restrictedZone);
const safeZone = ZoneTide.circle()
.id("starter")
.center(0, 0)
.radius(50)
.name("Starter Zone")
.type("safe")
.rules({ allowCombat : false })
.build();
await zone.createZone(safeZone);
await zone.track("player-001", { x : 60, y : 60 });🧱 Zone Definitions
📐 Built-in Shapes
| Method | Description |
|----------------------------|-----------------------------------------|
| ZoneTide.circle() | Creates a circle zone |
| ZoneTide.box() | Creates a rectangular box |
| ZoneTide.polygon() | Create a custom polygon zone |
| ZoneTide.union() | Combines multiple zones into one |
| ZoneTide.intersection() | Keeps only overlapping parts of zones |
| ZoneTide.difference() | Excludes one or more zones from a base |
🧩 Define Your Own Shape Types
Use setShapeRegistry() to register custom reusable shapes or aliases:
zone.setShapeRegistry({
"spawn-shape" : { shape : "circle", center : { x : 0, y : 0 }, radius : 75 },
"danger-zone" : { shape : "box", x : 50, y : 50, width : 100, height : 100 }
});Then reference them like so:
ZoneTide.zone()
.id("zone-1")
.shape("spawn-shape")
.build();📶 Zone Events
| Event | Triggered When... |
|------------|-----------------------------------------------|
| ENTER | Entity enters a new zone |
| EXIT | Entity leaves a zone |
| STAY | Entity remains in the same zone |
| VIOLATION| Entity enters a zone that disallows entry |
zone.on(ZoneTide.events.ENTER, ({ entityID, zoneID }) => {
console.log(`➡️ ${entityID} entered ${zoneID}`);
});🔍 Precomputed Evaluation
Check whether coordinates are inside specific zones, without tracking:
const match = await zone.getZonesContainingPosition({ x : 42, y : 5 }, {
zoneIDs : [ "safe-zone", "restricted-fort" ],
includeZoneObject : true
});
console.log(match.map(z => z.id));📡 Entity Tracking
await zone.track("entity-001", { x : 10, y : 5 });Stream positions:
zone.trackStream("bot-5", () => getEntityPosition(), 1000);🗂️ Load Zones From File
const zone = ZoneTide.fromConfigFile("./zones.json");zones.json Example
{
"zones": [
{
"id": "starter",
"shape": {
"shape": "circle",
"center": { "x": 0, "y": 0 },
"radius": 75
}
}
]
}📜 License
See LICENSE.md
🧠 Smarter Zones. Smarter Worlds.
ZoneTide empowers you to define, evaluate, and control space — so your systems can adapt, react, and scale like never before.
