@series-inc/rundot-3d-engine 0.6.18 → 0.6.20
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.
- package/SKILL.md +205 -1
- package/dist/{chunk-4BJMBHQA.js → chunk-ZLFLOH62.js} +595 -33
- package/dist/chunk-ZLFLOH62.js.map +1 -0
- package/dist/index.d.ts +25 -1
- package/dist/index.js +92 -383
- package/dist/index.js.map +1 -1
- package/dist/systems/index.d.ts +200 -31
- package/dist/systems/index.js +644 -1
- package/dist/systems/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4BJMBHQA.js.map +0 -1
package/SKILL.md
CHANGED
|
@@ -335,10 +335,214 @@ const clone = await stowkit.cloneMesh("name", castShadow, receiveShadow)
|
|
|
335
335
|
await stowkit.registerMeshForInstancing("coin_batch", "coin_mesh", true, true, 500)
|
|
336
336
|
```
|
|
337
337
|
|
|
338
|
+
### InputManager — Keyboard, Pointer, Touch & Custom Actions
|
|
339
|
+
|
|
340
|
+
The `InputManager` is a singleton that tracks keyboard, pointer, and touch state. Use the `Input` convenience object for quick access.
|
|
341
|
+
|
|
342
|
+
**Built-in action polling (keyboard):**
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
import { Input, InputAction } from "@series-inc/rundot-3d-engine/systems"
|
|
346
|
+
|
|
347
|
+
// Check built-in movement actions
|
|
348
|
+
if (Input.isPressed(InputAction.MOVE_FORWARD)) { /* W key */ }
|
|
349
|
+
if (Input.isKeyPressed("Space")) { /* raw key check */ }
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**Pointer & touch state:**
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
Input.isPointerDown() // true while mouse/pen is held
|
|
356
|
+
Input.getPointerPosition() // { x, y } in client coords
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
**Custom action system — register named actions with multiple trigger types:**
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
import { Input } from "@series-inc/rundot-3d-engine/systems"
|
|
363
|
+
import type { ActionTrigger } from "@series-inc/rundot-3d-engine/systems"
|
|
364
|
+
|
|
365
|
+
// Register an action with multiple triggers
|
|
366
|
+
Input.registerAction("jump", [
|
|
367
|
+
{ type: "key", code: "Space" },
|
|
368
|
+
{ type: "pointer" },
|
|
369
|
+
{ type: "touch" },
|
|
370
|
+
])
|
|
371
|
+
|
|
372
|
+
// Subscribe to action (fires on press) — returns unsubscribe function
|
|
373
|
+
const unsub = Input.onAction("jump", () => {
|
|
374
|
+
player.flap()
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
// Polling API
|
|
378
|
+
if (Input.isCustomActionActive("jump")) { /* any trigger held */ }
|
|
379
|
+
|
|
380
|
+
// Cleanup
|
|
381
|
+
unsub()
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**ActionTrigger types:**
|
|
385
|
+
- `{ type: "key", code: string }` — keyboard key (uses `event.code`, e.g. `"Space"`, `"KeyW"`)
|
|
386
|
+
- `{ type: "pointer" }` — mouse or pen pointer down (excludes touch — no double-firing)
|
|
387
|
+
- `{ type: "touch" }` — touch screen tap
|
|
388
|
+
|
|
389
|
+
**Notes:**
|
|
390
|
+
- On touch devices, pointer events from touch input are automatically skipped to prevent double-firing when an action has both `pointer` and `touch` triggers.
|
|
391
|
+
- `Input.setEnabled(false)` disables all input processing and clears all state.
|
|
392
|
+
- Custom actions registered with `registerAction` also get `preventDefault` on their key triggers.
|
|
393
|
+
|
|
394
|
+
### ShaderRegistry & ShaderComponent — Shader Library
|
|
395
|
+
|
|
396
|
+
A registry of named shader presets with a component that applies them to meshes. Shared `time` and `deltaTime` uniforms are updated automatically once per frame.
|
|
397
|
+
|
|
398
|
+
**Built-in presets:**
|
|
399
|
+
- `"fresnel"` — Fresnel rim lighting, wrap diffuse, specular, under-lighting, directional light. Good for stylized characters and objects.
|
|
400
|
+
- `"wind"` — Simplex noise-based vertex displacement for vegetation animation. Includes depth shader pair for correct shadow casting with alpha clip.
|
|
401
|
+
|
|
402
|
+
**Usage — apply a shader preset to a GameObject:**
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
import { ShaderComponent } from "@series-inc/rundot-3d-engine/systems"
|
|
406
|
+
|
|
407
|
+
// Apply fresnel shader with default settings
|
|
408
|
+
gameObject.addComponent(new ShaderComponent("fresnel"))
|
|
409
|
+
|
|
410
|
+
// Apply with uniform overrides
|
|
411
|
+
gameObject.addComponent(new ShaderComponent("fresnel", {
|
|
412
|
+
fresnelIntensity: { value: 0.3 },
|
|
413
|
+
underLightIntensity: { value: 0.2 },
|
|
414
|
+
}))
|
|
415
|
+
|
|
416
|
+
// Apply wind shader (vegetation)
|
|
417
|
+
seaweedObject.addComponent(new ShaderComponent("wind"))
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**ShaderComponent behavior:**
|
|
421
|
+
- Waits for all `MeshRenderer` components in children to load before applying
|
|
422
|
+
- Traverses all child meshes and replaces materials with ShaderMaterial from the preset
|
|
423
|
+
- Automatically includes fog uniforms and shared time uniforms
|
|
424
|
+
- Sets `preventAutoInstancing = true` (custom materials can't be auto-batched)
|
|
425
|
+
- On cleanup, restores original materials and disposes created shader materials
|
|
426
|
+
- For presets with depth shaders (e.g. `"wind"`), creates `customDepthMaterial` and `customDistanceMaterial` for correct shadow casting
|
|
427
|
+
|
|
428
|
+
**Registering custom presets:**
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
import { ShaderRegistry } from "@series-inc/rundot-3d-engine/systems"
|
|
432
|
+
import type { ShaderPreset } from "@series-inc/rundot-3d-engine/systems"
|
|
433
|
+
|
|
434
|
+
ShaderRegistry.register({
|
|
435
|
+
name: "myShader",
|
|
436
|
+
vertexShader: `...`,
|
|
437
|
+
fragmentShader: `...`,
|
|
438
|
+
depthVertexShader: `...`, // optional — for shadow casting
|
|
439
|
+
depthFragmentShader: `...`, // optional
|
|
440
|
+
side: THREE.FrontSide, // optional (default: FrontSide)
|
|
441
|
+
transparent: false, // optional (default: false)
|
|
442
|
+
fog: true, // optional (default: true)
|
|
443
|
+
toneMapped: false, // optional (default: false)
|
|
444
|
+
defaultUniforms: {
|
|
445
|
+
myColor: { value: new THREE.Color(1, 0, 0) },
|
|
446
|
+
myFloat: { value: 1.0 },
|
|
447
|
+
},
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
// Then use it
|
|
451
|
+
gameObject.addComponent(new ShaderComponent("myShader"))
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Shared uniforms (available in all shader presets):**
|
|
455
|
+
- `time` (float) — `performance.now() * 0.001` (seconds since page load)
|
|
456
|
+
- `deltaTime` (float) — frame delta time
|
|
457
|
+
- `baseMap` (sampler2D) — automatically set from the mesh's existing texture map
|
|
458
|
+
|
|
459
|
+
**Fresnel preset uniforms:** `sunDir`, `sunColor`, `sunIntensity`, `fresnelColor`, `fresnelPower`, `fresnelIntensity`, `ambientColor`, `ambientIntensity`, `specColor`, `specShininess`, `specIntensity`, `underLightColor`, `underLightIntensity`, `underLightPower`, `rimLightDir`, `rimLightColor`, `rimLightIntensity`
|
|
460
|
+
|
|
461
|
+
**Wind preset uniforms:** `windStrength`, `windSpeed`, `rootWorldOrigin`, `alphaClip`, `tintColor`, `lightDir`, `ambientColor`, `ambientStrength`
|
|
462
|
+
|
|
463
|
+
### ObjectPool, GameObjectPool & ScrollingPool — Object Pooling
|
|
464
|
+
|
|
465
|
+
Generic and specialized pools for reusing objects instead of creating/destroying them each frame.
|
|
466
|
+
|
|
467
|
+
**ObjectPool — generic pool:**
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
import { ObjectPool } from "@series-inc/rundot-3d-engine/systems"
|
|
471
|
+
|
|
472
|
+
const pool = new ObjectPool({
|
|
473
|
+
create: () => new Bullet(),
|
|
474
|
+
onAcquire: (b) => b.activate(),
|
|
475
|
+
onRelease: (b) => b.deactivate(),
|
|
476
|
+
onDestroy: (b) => b.dispose(),
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
pool.warm(20) // pre-allocate 20 objects
|
|
480
|
+
const bullet = pool.acquire() // get from pool (or create new)
|
|
481
|
+
pool.release(bullet) // return to pool
|
|
482
|
+
pool.releaseAll() // return all active objects
|
|
483
|
+
pool.dispose() // destroy everything
|
|
484
|
+
|
|
485
|
+
pool.activeCount // currently in use
|
|
486
|
+
pool.availableCount // ready to acquire
|
|
487
|
+
pool.totalCount // active + available
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
**GameObjectPool — pool for GameObjects with visibility management:**
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
import { GameObjectPool } from "@series-inc/rundot-3d-engine/systems"
|
|
494
|
+
|
|
495
|
+
const pipePool = new GameObjectPool(() => {
|
|
496
|
+
const go = new GameObject("Pipe")
|
|
497
|
+
go.addComponent(new MeshRenderer("pipe_mesh"))
|
|
498
|
+
return go
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
pipePool.warm(10)
|
|
502
|
+
const pipe = pipePool.acquire() // visible = true
|
|
503
|
+
pipe.position.set(0, 0, 50)
|
|
504
|
+
|
|
505
|
+
pipePool.release(pipe) // visible = false, moved offscreen (y = -9999)
|
|
506
|
+
pipePool.releaseAll()
|
|
507
|
+
pipePool.dispose() // calls gameObject.dispose() on all
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**ScrollingPool — infinite tile recycler for endless/runner games:**
|
|
511
|
+
|
|
512
|
+
```typescript
|
|
513
|
+
import { ScrollingPool, GameObjectPool } from "@series-inc/rundot-3d-engine/systems"
|
|
514
|
+
|
|
515
|
+
const tilePool = new GameObjectPool(() => {
|
|
516
|
+
const tile = Prefabs.instantiate("Background").gameObject
|
|
517
|
+
return tile
|
|
518
|
+
})
|
|
519
|
+
|
|
520
|
+
const scroller = new ScrollingPool({
|
|
521
|
+
pool: tilePool,
|
|
522
|
+
tileSize: 250,
|
|
523
|
+
bufferCount: 3,
|
|
524
|
+
axis: "z", // "x" | "y" | "z" (default: "z")
|
|
525
|
+
onSpawn: (tile, index) => {
|
|
526
|
+
// customize each spawned tile
|
|
527
|
+
tile.position.x = 25
|
|
528
|
+
},
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
scroller.initialize() // spawn initial buffer
|
|
532
|
+
|
|
533
|
+
// In update loop:
|
|
534
|
+
scroller.update(playerZ) // spawns ahead, recycles behind
|
|
535
|
+
|
|
536
|
+
// On restart:
|
|
537
|
+
scroller.reset()
|
|
538
|
+
scroller.initialize()
|
|
539
|
+
|
|
540
|
+
scroller.dispose()
|
|
541
|
+
```
|
|
542
|
+
|
|
338
543
|
### Other Systems
|
|
339
544
|
|
|
340
545
|
- **AudioSystem** — 2D/3D positional audio with AudioListener management
|
|
341
|
-
- **InputManager** — keyboard, mouse, touch, and gamepad input
|
|
342
546
|
- **LightingSystem** — directional, point, and spot lights with shadow management
|
|
343
547
|
- **NavigationSystem** — A* pathfinding on navigation meshes
|
|
344
548
|
- **ParticleSystem** — GPU particle effects
|