npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@starweave/roblox

v0.1.4

Published

Vedic astrology-driven NPC behavior SDK for Roblox

Readme

@starweave/roblox

Vedic astrology-driven NPC behavior SDK for Roblox. Give your NPCs unique personalities, moods, relationships, and daily routines — all computed from birth charts.

Install

roblox-ts (TypeScript):

npm install @starweave/roblox

Luau (native): Download Starweave.rbxm from Releases and insert it into ReplicatedStorage.

Quick Start

import { NPCSpawner, DEFAULT_SPAWNER_CONFIG } from "@starweave/roblox";

// 1. Create a spawner with your API credentials
const spawner = new NPCSpawner({
  ...DEFAULT_SPAWNER_CONFIG,
  api_base_url: "https://starweave.whimco.com",
  api_key: "your-api-key",
});

// 2. Spawn an NPC — birth_time determines their entire personality
await spawner.spawnNPC({
  npc_id: "merchant_01",
  birth_time: "1985-06-15T14:30:00Z",
  model: workspace.NPCs.Merchant,
  spawn_position: new Vector3(10, 5, 20),
});

// 3. Start the behavior loop
spawner.startUpdateLoop();

// 4. Read NPC state anytime
const behavior = spawner.getNPCBehavior("merchant_01");
// → {
//     current_activity: "trading",
//     mood_expression: "content",
//     movement_style: "walk",
//     social_disposition: "friendly",
//     is_busy: false,
//   }

How It Works

Each NPC gets a birth time (ISO 8601 string). The Starweave engine computes a Vedic birth chart and derives:

  • Static Profile (permanent): base personality traits, behavioral flags, preferred activities, daily schedule variance
  • Dynamic State (changes over time): current dasha period, active planetary transits, mood, motivation, temporary trait shifts
  • Relational State (per relationship): trust, familiarity, social disposition toward players and other NPCs

The SDK handles all API calls, caching, and state management. You just read the results.

API

NPCSpawner

The main entry point. Manages NPC lifecycle, behavior updates, and proximity detection.

const spawner = new NPCSpawner(config: SpawnerConfig);

SpawnerConfig

| Field | Type | Default | Description | |-------|------|---------|-------------| | api_base_url | string | required | Your Starweave API URL | | api_key | string | required | API key for authentication | | update_interval | number | 5 | Seconds between behavior recalculations | | dynamic_refresh | number | 300 | Seconds between dynamic state API refreshes | | proximity_radius | number | 20 | Studs for player/NPC detection | | proximity_check_interval | number | 1 | Seconds between proximity scans | | cache_ttl_seconds | number | 300 | Seconds to cache API responses |

Use DEFAULT_SPAWNER_CONFIG to start with sensible defaults and override what you need:

const spawner = new NPCSpawner({
  ...DEFAULT_SPAWNER_CONFIG,
  api_base_url: "https://starweave.whimco.com",
  api_key: "your-api-key",
  proximity_radius: 50, // wider awareness range
});

Methods

// Spawn a single NPC
await spawner.spawnNPC({
  npc_id: "guard_01",
  birth_time: "1972-03-22T08:15:00Z",
  model: workspace.NPCs.Guard,
  spawn_position: new Vector3(0, 5, 0), // optional
}): Promise<boolean>

// Spawn multiple NPCs
await spawner.spawnBatch(definitions): Promise<number> // returns count spawned

// Start the global update loop (call once after spawning)
spawner.startUpdateLoop(): void

// Query NPC state
spawner.getNPCBehavior(npcId): BehaviorState | undefined
spawner.getNPCProfile(npcId): StaticProfile | undefined
spawner.getController(npcId): NPCBehaviorController | undefined

// Cleanup
spawner.removeNPC(npcId): void
spawner.destroy(): void

NPCBehaviorController

Lower-level controller for a single NPC. Use this if you want manual control instead of NPCSpawner.

const controller = new NPCBehaviorController(config, vedicService);
await controller.initialize();

// Called every frame (or on a timer)
controller.update(dt);

// Proximity events
await controller.onPlayerProximity(player);
await controller.onNPCProximity(otherNpcId, otherProfile);

// Record interactions (trades, combat, conversations)
controller.recordInteraction(targetId, "traded_sword");

// Read state
controller.getBehavior(): BehaviorState
controller.getStaticProfile(): StaticProfile | undefined
controller.getDynamicState(): DynamicState | undefined
controller.getRelationship(targetId): RelationalState | undefined

BehaviorState

What you read from an NPC at any moment:

interface BehaviorState {
  current_activity: string;       // "idle", "trading", "patrolling", "meditating", ...
  target_entity?: string;         // player/NPC they're focused on
  mood_expression: string;        // "joyful", "content", "neutral", "anxious", "angry"
  movement_style: "idle" | "walk" | "run" | "sneak" | "patrol";
  social_disposition: "friendly" | "neutral" | "wary" | "hostile";
  is_busy: boolean;
}

VedicService

Direct API client if you want to make raw calls:

const service = new VedicService({
  baseUrl: "https://starweave.whimco.com",
  apiKey: "your-api-key",
  cacheTtlSeconds: 300,
});

const profile = await service.getStaticProfile({
  npc_id: "npc_01",
  birth_time: "1990-04-15T06:30:00Z",
});

const dynamic = await service.getDynamicState({
  npc_id: "npc_01",
  current_time: os.date("!%Y-%m-%dT%H:%M:%SZ"),
  static_profile: profile,
});

service.clearCache();
service.clearCacheForNPC("npc_01");

Birth Time Guide

Birth time is the only input that matters. It determines everything about an NPC's personality through Vedic astrology:

  • Lagna (Ascendant): Core personality archetype (12 types)
  • Moon Nakshatra: Emotional texture and behavioral nuance (27 types)
  • Planetary Aspects: Behavioral flags like territorial, merchant, healer
  • Dasha Period: Current life phase and motivation (changes over time)

Tips for variety:

  • Spread birth times across a 120-year window (1920-01-01 to 2040-01-01) — NPCs born in the same decade will share similar dasha phases
  • Different birth times on the same day still produce different lagnas (ascendant changes every ~2 hours)
  • Store birth times in your NPC data — they never change and the static profile is computed once
// Good: diverse birth times
const npcs = [
  { npc_id: "elder",    birth_time: "1935-11-02T04:00:00Z", model: ... },
  { npc_id: "merchant", birth_time: "1978-07-19T16:45:00Z", model: ... },
  { npc_id: "guard",    birth_time: "2001-01-30T09:20:00Z", model: ... },
];

Configuration Tuning

| Scenario | update_interval | dynamic_refresh | proximity_radius | cache_ttl | |----------|----------------|----------------|-----------------|-----------| | Active NPCs (shops, quest givers) | 2-3s | 300s | 20 studs | 300s | | Background NPCs (crowds, ambient) | 10-30s | 600s | 50 studs | 600s | | Large scenes (50+ NPCs) | 5s | 900s | 30 studs | 900s |

Key rule: dynamic_refresh should equal cache_ttl_seconds. Refreshing faster than the cache wastes API calls; refreshing slower causes stale state.

Types

All Vedic types are exported for TypeScript users:

import type {
  StaticProfile,
  DynamicState,
  RelationalState,
  TraitBlock,
  BehavioralFlag,
  PlanetaryPosition,
  DashaPeriod,
  Transit,
  ZodiacSign,
  Nakshatra,
  Planet,
} from "@starweave/roblox";

TraitBlock

The five core personality dimensions (0.0 to 1.0):

interface TraitBlock {
  openness: number;            // curiosity, willingness to explore
  loyalty: number;             // faithfulness, attachment strength
  aggression: number;          // combativeness, territorial instinct
  fear: number;                // anxiety, caution level
  deception_tendency: number;  // cunning, willingness to deceive
}

License

MIT — Whimco Studio