@jgengine/core 0.4.0 → 0.6.0

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 (51) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/dist/game/defineGame.d.ts +3 -0
  3. package/dist/game/feed.d.ts +2 -0
  4. package/dist/game/feed.js +10 -8
  5. package/dist/game/playableGame.d.ts +10 -1
  6. package/dist/game/progression.d.ts +61 -0
  7. package/dist/game/progression.js +96 -0
  8. package/dist/game/quest.d.ts +39 -0
  9. package/dist/game/quest.js +195 -0
  10. package/dist/game/trade.d.ts +23 -0
  11. package/dist/game/trade.js +50 -8
  12. package/dist/game/unlocks.d.ts +9 -0
  13. package/dist/game/unlocks.js +19 -1
  14. package/dist/inventory/slotModel.d.ts +19 -0
  15. package/dist/inventory/slotModel.js +76 -0
  16. package/dist/meta/changelog.d.ts +8 -0
  17. package/dist/meta/changelog.js +43 -0
  18. package/dist/physics/physicsWorld.d.ts +136 -0
  19. package/dist/physics/physicsWorld.js +489 -0
  20. package/dist/runtime/gameContext.d.ts +2 -0
  21. package/dist/runtime/gameContext.js +3 -0
  22. package/dist/scene/assetCatalog.d.ts +13 -0
  23. package/dist/scene/entityStore.d.ts +6 -0
  24. package/dist/scene/entityStore.js +15 -1
  25. package/dist/time/simClock.d.ts +62 -0
  26. package/dist/time/simClock.js +132 -0
  27. package/dist/world/buildingIndex.d.ts +16 -0
  28. package/dist/world/buildingIndex.js +63 -0
  29. package/dist/world/buildings.d.ts +98 -0
  30. package/dist/world/buildings.js +320 -0
  31. package/dist/world/features.d.ts +105 -1
  32. package/dist/world/features.js +95 -0
  33. package/dist/world/geometry.d.ts +23 -0
  34. package/dist/world/geometry.js +75 -0
  35. package/dist/world/interiors.d.ts +35 -0
  36. package/dist/world/interiors.js +66 -0
  37. package/dist/world/placement.d.ts +30 -0
  38. package/dist/world/placement.js +20 -0
  39. package/dist/world/regions.d.ts +66 -0
  40. package/dist/world/regions.js +158 -0
  41. package/dist/world/scatter.d.ts +24 -0
  42. package/dist/world/scatter.js +126 -0
  43. package/dist/world/scatterItems.d.ts +38 -0
  44. package/dist/world/scatterItems.js +85 -0
  45. package/dist/world/terrain.d.ts +54 -0
  46. package/dist/world/terrain.js +181 -0
  47. package/dist/world/water.d.ts +27 -0
  48. package/dist/world/water.js +125 -0
  49. package/dist/world/wind.d.ts +17 -0
  50. package/dist/world/wind.js +40 -0
  51. package/package.json +5 -2
@@ -0,0 +1,27 @@
1
+ import type { OceanEnvironmentDescriptor } from "./features.js";
2
+ export type WaterNormal = readonly [number, number, number];
3
+ export interface GerstnerWave {
4
+ direction: readonly [number, number];
5
+ wavelength: number;
6
+ amplitude: number;
7
+ steepness: number;
8
+ speed: number;
9
+ }
10
+ export interface WaterSurfaceConfig {
11
+ level?: number;
12
+ waveHeight?: number;
13
+ waveScale?: number;
14
+ waveSpeed?: number;
15
+ waves?: number;
16
+ choppiness?: number;
17
+ }
18
+ export interface WaterSurface {
19
+ readonly level: number;
20
+ readonly waves: readonly GerstnerWave[];
21
+ height(x: number, z: number, time: number): number;
22
+ normal(x: number, z: number, time: number): WaterNormal;
23
+ displace(x: number, z: number, time: number): readonly [number, number, number];
24
+ }
25
+ export declare function synthesizeWaves(config?: WaterSurfaceConfig): GerstnerWave[];
26
+ export declare function waterSurface(config?: WaterSurfaceConfig): WaterSurface;
27
+ export declare function waterSurfaceFromDescriptor(descriptor: OceanEnvironmentDescriptor, waves?: number): WaterSurface;
@@ -0,0 +1,125 @@
1
+ const GRAVITY = 9.81;
2
+ const TWO_PI = Math.PI * 2;
3
+ const AMPLITUDE_FALLOFF = 0.65;
4
+ const WAVELENGTH_FALLOFF = 0.65;
5
+ const DIRECTION_SPREAD = 0.62;
6
+ function resolveConfig(config) {
7
+ return {
8
+ level: config.level ?? 0,
9
+ waveHeight: config.waveHeight ?? 1.2,
10
+ waveScale: config.waveScale ?? 18,
11
+ waveSpeed: config.waveSpeed ?? 0.55,
12
+ waves: config.waves ?? 4,
13
+ choppiness: config.choppiness ?? 1,
14
+ };
15
+ }
16
+ export function synthesizeWaves(config = {}) {
17
+ const resolved = resolveConfig(config);
18
+ const count = Math.max(0, Math.floor(resolved.waves));
19
+ if (count === 0 || resolved.waveHeight <= 0) {
20
+ return [];
21
+ }
22
+ let amplitudeSum = 0;
23
+ for (let i = 0; i < count; i += 1) {
24
+ amplitudeSum += AMPLITUDE_FALLOFF ** i;
25
+ }
26
+ const amplitudeUnit = resolved.waveHeight / amplitudeSum;
27
+ const waves = [];
28
+ for (let i = 0; i < count; i += 1) {
29
+ const amplitude = amplitudeUnit * AMPLITUDE_FALLOFF ** i;
30
+ const wavelength = resolved.waveScale * WAVELENGTH_FALLOFF ** i;
31
+ const k = TWO_PI / wavelength;
32
+ const angle = DIRECTION_SPREAD * (i % 2 === 0 ? 1 : -1) * Math.ceil(i / 2);
33
+ const direction = [Math.cos(angle), Math.sin(angle)];
34
+ const omega = Math.sqrt(GRAVITY * k) * resolved.waveSpeed;
35
+ const speed = omega / k;
36
+ const steepnessLimit = 1 / (k * amplitude * count);
37
+ const steepness = Math.min(1, Math.max(0, 0.4 * steepnessLimit));
38
+ waves.push({ direction, wavelength, amplitude, steepness, speed });
39
+ }
40
+ return waves;
41
+ }
42
+ export function waterSurface(config = {}) {
43
+ const resolved = resolveConfig(config);
44
+ const level = resolved.level;
45
+ const choppiness = resolved.choppiness;
46
+ const waves = synthesizeWaves(config);
47
+ const height = (x, z, time) => {
48
+ let y = level;
49
+ for (const wave of waves) {
50
+ const k = TWO_PI / wave.wavelength;
51
+ const omega = wave.speed * k;
52
+ const phase = k * (wave.direction[0] * x + wave.direction[1] * z) - omega * time;
53
+ y += wave.amplitude * Math.sin(phase);
54
+ }
55
+ return y;
56
+ };
57
+ const displace = (x, z, time) => {
58
+ let dx = x;
59
+ let dz = z;
60
+ let dy = level;
61
+ for (const wave of waves) {
62
+ const k = TWO_PI / wave.wavelength;
63
+ const omega = wave.speed * k;
64
+ const phase = k * (wave.direction[0] * x + wave.direction[1] * z) - omega * time;
65
+ const cosPhase = Math.cos(phase);
66
+ const q = wave.steepness;
67
+ dx += q * wave.amplitude * choppiness * wave.direction[0] * cosPhase;
68
+ dz += q * wave.amplitude * choppiness * wave.direction[1] * cosPhase;
69
+ dy += wave.amplitude * Math.sin(phase);
70
+ }
71
+ return [dx, dy, dz];
72
+ };
73
+ const normal = (x, z, time) => {
74
+ let tx = 1;
75
+ let ty = 0;
76
+ let tz = 0;
77
+ let bx = 0;
78
+ let by = 0;
79
+ let bz = 1;
80
+ for (const wave of waves) {
81
+ const k = TWO_PI / wave.wavelength;
82
+ const omega = wave.speed * k;
83
+ const phase = k * (wave.direction[0] * x + wave.direction[1] * z) - omega * time;
84
+ const cosPhase = Math.cos(phase);
85
+ const sinPhase = Math.sin(phase);
86
+ const wa = k * wave.amplitude;
87
+ const q = wave.steepness;
88
+ const dxWave = wave.direction[0];
89
+ const dzWave = wave.direction[1];
90
+ tx += -q * dxWave * dxWave * wa * choppiness * sinPhase;
91
+ ty += dxWave * wa * cosPhase;
92
+ tz += -q * dxWave * dzWave * wa * choppiness * sinPhase;
93
+ bx += -q * dxWave * dzWave * wa * choppiness * sinPhase;
94
+ by += dzWave * wa * cosPhase;
95
+ bz += -q * dzWave * dzWave * wa * choppiness * sinPhase;
96
+ }
97
+ let nx = by * tz - bz * ty;
98
+ let ny = bz * tx - bx * tz;
99
+ let nz = bx * ty - by * tx;
100
+ const lengthSq = nx * nx + ny * ny + nz * nz;
101
+ if (lengthSq === 0) {
102
+ return [0, 1, 0];
103
+ }
104
+ const inv = 1 / Math.sqrt(lengthSq);
105
+ nx *= inv;
106
+ ny *= inv;
107
+ nz *= inv;
108
+ if (ny < 0) {
109
+ nx = -nx;
110
+ ny = -ny;
111
+ nz = -nz;
112
+ }
113
+ return [nx, ny, nz];
114
+ };
115
+ return { level, waves, height, normal, displace };
116
+ }
117
+ export function waterSurfaceFromDescriptor(descriptor, waves) {
118
+ return waterSurface({
119
+ level: descriptor.level,
120
+ waveHeight: descriptor.waveHeight,
121
+ waveScale: descriptor.waveScale,
122
+ waveSpeed: descriptor.waveSpeed,
123
+ ...(waves === undefined ? {} : { waves }),
124
+ });
125
+ }
@@ -0,0 +1,17 @@
1
+ export type WindVector = readonly [number, number];
2
+ export interface WindFieldConfig {
3
+ direction?: WindVector;
4
+ speed?: number;
5
+ gust?: number;
6
+ gustFrequency?: number;
7
+ turbulence?: number;
8
+ seed?: string | number;
9
+ }
10
+ export interface WindField {
11
+ readonly direction: WindVector;
12
+ readonly speed: number;
13
+ at(time: number): WindVector;
14
+ atPoint(x: number, z: number, time: number): WindVector;
15
+ strengthAt(x: number, z: number, time: number): number;
16
+ }
17
+ export declare function windField(config?: WindFieldConfig): WindField;
@@ -0,0 +1,40 @@
1
+ import { fractalNoise, seedFrom, valueNoise } from "./terrain.js";
2
+ const WIND_SEED_FALLBACK = 0x77696e64;
3
+ function normalizeDirection(direction) {
4
+ const length = Math.hypot(direction[0], direction[1]);
5
+ if (length === 0)
6
+ return [1, 0];
7
+ return [direction[0] / length, direction[1] / length];
8
+ }
9
+ export function windField(config = {}) {
10
+ const direction = normalizeDirection(config.direction ?? [1, 0]);
11
+ const speed = config.speed ?? 1;
12
+ const gust = config.gust ?? 0;
13
+ const gustFrequency = config.gustFrequency ?? 0.15;
14
+ const turbulence = config.turbulence ?? 0;
15
+ const seed = seedFrom(config.seed, WIND_SEED_FALLBACK);
16
+ const at = (time) => {
17
+ const gustAmt = gust *
18
+ fractalNoise(time * gustFrequency, 0, {
19
+ seed,
20
+ frequency: 1,
21
+ octaves: 3,
22
+ lacunarity: 2,
23
+ persistence: 0.5,
24
+ ridged: false,
25
+ });
26
+ const magnitude = speed + gustAmt;
27
+ return [direction[0] * magnitude, direction[1] * magnitude];
28
+ };
29
+ const atPoint = (x, z, time) => {
30
+ const base = at(time);
31
+ const tx = valueNoise(x * 0.05 + time * 0.1, z * 0.05, seed);
32
+ const tz = valueNoise(z * 0.05, x * 0.05 - time * 0.1, seed + 101);
33
+ return [base[0] + turbulence * tx, base[1] + turbulence * tz];
34
+ };
35
+ const strengthAt = (x, z, time) => {
36
+ const [wx, wz] = atPoint(x, z, time);
37
+ return Math.hypot(wx, wz);
38
+ };
39
+ return { direction, speed, at, atPoint, strengthAt };
40
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jgengine/core",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Genre-agnostic TypeScript game engine SDK: game runtime, state store, entity scene, combat, movement, inventory, economy, quests, multiplayer primitives.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
@@ -10,7 +10,10 @@
10
10
  "url": "git+https://github.com/Noisemaker111/jgengine.git",
11
11
  "directory": "packages/core"
12
12
  },
13
- "files": ["dist"],
13
+ "files": [
14
+ "dist",
15
+ "CHANGELOG.md"
16
+ ],
14
17
  "exports": {
15
18
  ".": {
16
19
  "types": "./dist/index.d.ts",