Skip to content

Commit 5b02fb0

Browse files
authored
Merge pull request #29 from lucent-lab/feature/camera-2d
feat: add 2d camera system
2 parents 88feb8d + 3694865 commit 5b02fb0

9 files changed

Lines changed: 589 additions & 21 deletions

File tree

PROJECT_DESCRIPTION.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ npm run build
3838
| Grid pathfinding | `astar`, `dijkstra`, `jumpPointSearch`, `computeFlowField`, `buildNavMesh`, `findNavMeshPath`, `manhattanDistance`, `gridFromString` | `pathfinding/astar.ts`, `pathfinding/dijkstra.ts`, `pathfinding/jumpPointSearch.ts`, `pathfinding/flowField.ts`, `pathfinding/navMesh.ts` | `examples/astar.ts`, `examples/flowField.ts`, `examples/navMesh.ts` |
3939
| Procedural textures & terrain | `perlin`, `perlin3D`, `simplex2D`, `simplex3D`, `worley`, `worleySample`, `waveFunctionCollapse`, `cellularAutomataCave`, `poissonDiskSampling`, `computeVoronoiDiagram`, `diamondSquare`, `generateLSystem`, `generateBspDungeon`, `generateRecursiveMaze`, `generatePrimMaze`, `generateKruskalMaze`, `generateWilsonMaze`, `generateAldousBroderMaze`, `generateRecursiveDivisionMaze` | `procedural/*.ts` | `examples/simplex.ts`, `examples/worley.ts`, `examples/waveFunctionCollapse.ts`, `examples/cellularAutomata.ts`, `examples/poissonDisk.ts`, `examples/voronoi.ts`, `examples/diamondSquare.ts`, `examples/lSystem.ts`, `examples/dungeonBsp.ts`, `examples/mazeRecursive.ts`, `examples/mazePrim.ts`, `examples/mazeKruskal.ts`, `examples/mazeWilson.ts`, `examples/mazeAldous.ts`, `examples/mazeDivision.ts` |
4040
| Spatial queries & collision | `Quadtree`, `aabbCollision`, `aabbIntersection`, `satCollision`, `circleRayIntersection`, `sweptAABB` | `spatial/*.ts` | `examples/sat.ts` |
41-
| Web performance & UI throttling | `debounce`, `throttle`, `LRUCache`, `memoize`, `deduplicateRequest`, `clearRequestDedup`, `calculateVirtualRange`, `createWeightedAliasSampler`, `createObjectPool`, `fisherYatesShuffle`, `createFixedTimestepLoop` | `util/*.ts` | `examples/requestDedup.ts`, `examples/virtualScroll.ts`, `examples/weightedAlias.ts`, `examples/objectPool.ts`, `examples/fisherYates.ts`, `examples/fixedTimestep.ts` |
41+
| Web performance & UI throttling | `debounce`, `throttle`, `LRUCache`, `memoize`, `deduplicateRequest`, `clearRequestDedup`, `calculateVirtualRange`, `createWeightedAliasSampler`, `createObjectPool`, `fisherYatesShuffle` | `util/*.ts` | `examples/requestDedup.ts`, `examples/virtualScroll.ts`, `examples/weightedAlias.ts`, `examples/objectPool.ts`, `examples/fisherYates.ts` |
42+
| Gameplay systems | `createDeltaTimeManager`, `createFixedTimestepLoop`, `createCamera2D` | `util/deltaTime.ts`, `util/fixedTimestep.ts`, `gameplay/camera2D.ts` | `examples/deltaTime.ts`, `examples/fixedTimestep.ts`, `examples/camera2D.ts` |
4243
| Text & search | `fuzzySearch`, `fuzzyScore`, `Trie`, `binarySearch`, `levenshteinDistance` | `search/*.ts` | `examples/search.ts` |
4344
| Data transforms & diffing | `diff`, `deepClone`, `groupBy`, `diffJson`, `applyJsonDiff` | `data/*.ts` | `examples/jsonDiff.ts` |
4445
| Graph traversal | `graphBFS`, `graphDFS`, `topologicalSort` | `graph/traversal.ts` | `examples/graph.ts` |
@@ -60,6 +61,7 @@ llm-algorithms/
6061
│ ├── ai/
6162
│ ├── data/
6263
│ ├── geometry/
64+
│ ├── gameplay/
6365
│ ├── graph/
6466
│ ├── pathfinding/
6567
│ ├── procedural/
@@ -91,11 +93,12 @@ Consistency between runtime code, documentation, and TypeScript declarations kee
9193
- **Pathfinding:** A*, Dijkstra, Jump Point Search, flow field integration, Manhattan heuristic, grid string parser.
9294
- **Procedural:** 2D/3D Perlin, Worley noise, Wave Function Collapse tile synthesis.
9395
- **Spatial:** Quadtree, AABB helpers, SAT convex polygon collision.
94-
- **Performance utilities:** Debounce, throttle, LRU cache, memoize, request deduplication, virtual scrolling.
96+
- **Performance utilities:** Debounce, throttle, LRU cache, memoize, request deduplication, virtual scrolling, weighted alias sampling, object pooling, Fisher–Yates shuffle.
97+
- **Gameplay systems:** Delta-time manager, fixed timestep loop, 2D camera with smoothing and shake.
9598
- **Search:** Fuzzy search + scoring, Trie-based autocomplete, binary search, Levenshtein distance.
9699
- **Data tools:** Diff operations (LCS), deep clone, groupBy, JSON diff/patch helpers.
97100
- **Graph:** BFS distance map, DFS traversal, topological sort.
98-
- **Geometry & visuals:** Convex hull, line intersection, point-in-polygon, easing presets, quadratic/cubic Bezier evaluation.
101+
- **Geometry & visuals:** Convex hull, line intersection, point-in-polygon, Bresenham line rasterisation, easing presets, quadratic/cubic Bezier evaluation.
99102
- **AI behaviours:** Steering behaviours (seek, flee, arrive, pursue, wander), boids, behaviour trees, RVO crowd steering.
100103

101104
---

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ CDN usage:
2828
| Procedural generation | `perlin`, `perlin3D`, `simplex2D`, `simplex3D`, `worley`, `worleySample`, `waveFunctionCollapse`, `cellularAutomataCave`, `poissonDiskSampling`, `computeVoronoiDiagram`, `diamondSquare`, `generateLSystem`, `generateBspDungeon`, `generateRecursiveMaze`, `generatePrimMaze`, `generateKruskalMaze`, `generateWilsonMaze`, `generateAldousBroderMaze`, `generateRecursiveDivisionMaze` | `procedural/*.ts` | `examples/simplex.ts`, `examples/worley.ts`, `examples/waveFunctionCollapse.ts`, `examples/cellularAutomata.ts`, `examples/poissonDisk.ts`, `examples/voronoi.ts`, `examples/diamondSquare.ts`, `examples/lSystem.ts`, `examples/dungeonBsp.ts`, `examples/mazeRecursive.ts`, `examples/mazePrim.ts`, `examples/mazeKruskal.ts`, `examples/mazeWilson.ts`, `examples/mazeAldous.ts`, `examples/mazeDivision.ts` |
2929
| Spatial queries & collision | `Quadtree`, `aabbCollision`, `aabbIntersection`, `satCollision`, `circleRayIntersection`, `sweptAABB` | `spatial/*.ts` | `examples/sat.ts` |
3030
| AI behaviours & crowds | `seek`, `flee`, `arrive`, `pursue`, `wander`, `updateBoids`, `BehaviorTree`, `rvoStep` | `ai/steering.ts`, `ai/boids.ts`, `ai/behaviorTree.ts`, `ai/rvo.ts` | `examples/steering.ts`, `examples/boids.ts`, `examples/rvo.ts` |
31-
| Web performance & UI | `debounce`, `throttle`, `LRUCache`, `memoize`, `deduplicateRequest`, `clearRequestDedup`, `calculateVirtualRange`, `createWeightedAliasSampler`, `createObjectPool`, `createDeltaTimeManager`, `createFixedTimestepLoop`, `fisherYatesShuffle` | `util/*.ts` | `examples/requestDedup.ts`, `examples/virtualScroll.ts`, `examples/weightedAlias.ts`, `examples/objectPool.ts`, `examples/deltaTime.ts`, `examples/fixedTimestep.ts`, `examples/fisherYates.ts` |
31+
| Web performance & UI | `debounce`, `throttle`, `LRUCache`, `memoize`, `deduplicateRequest`, `clearRequestDedup`, `calculateVirtualRange`, `createWeightedAliasSampler`, `createObjectPool`, `fisherYatesShuffle` | `util/*.ts` | `examples/requestDedup.ts`, `examples/virtualScroll.ts`, `examples/weightedAlias.ts`, `examples/objectPool.ts`, `examples/fisherYates.ts` |
32+
| Gameplay systems | `createDeltaTimeManager`, `createFixedTimestepLoop`, `createCamera2D` | `util/deltaTime.ts`, `util/fixedTimestep.ts`, `gameplay/camera2D.ts` | `examples/deltaTime.ts`, `examples/fixedTimestep.ts`, `examples/camera2D.ts` |
3233
| Search & text | `fuzzySearch`, `fuzzyScore`, `Trie`, `binarySearch`, `levenshteinDistance` | `search/*.ts` | `examples/search.ts` |
3334
| Data & diff pipelines | `diff`, `deepClone`, `groupBy`, `diffJson`, `applyJsonDiff` | `data/*.ts` | `examples/jsonDiff.ts` |
3435
| Graph algorithms | `graphBFS`, `graphDFS`, `topologicalSort` | `graph/traversal.ts` | `examples/graph.ts` |
@@ -52,7 +53,7 @@ npm run size # Enforce bundle size budget
5253
- Milestone 0.2 next targets crowd-flow integrations (RVO + flow fields) and behaviour-tree decorators for richer AI control.
5354
- Milestone 0.4 plans a procedural + gameplay systems toolkit (Wave Function Collapse, dungeon suite, L-systems, game loop, camera, particles, inventory, combat, save/load, and more).
5455

55-
Examples live under `examples/` and can be executed with `tsx`/`ts-node` or compiled for the browser. See `examples/astar.ts`, `examples/flowField.ts`, `examples/navMesh.ts`, `examples/cellularAutomata.ts`, `examples/poissonDisk.ts`, `examples/voronoi.ts`, `examples/diamondSquare.ts`, `examples/lSystem.ts`, `examples/dungeonBsp.ts`, `examples/mazeRecursive.ts`, `examples/mazePrim.ts`, `examples/mazeKruskal.ts`, `examples/mazeWilson.ts`, `examples/mazeAldous.ts`, `examples/mazeDivision.ts`, `examples/steering.ts`, `examples/boids.ts`, `examples/requestDedup.ts`, `examples/search.ts`, `examples/graph.ts`, `examples/geometry.ts`, `examples/visual.ts`, `examples/sat.ts`, `examples/simplex.ts`, and `examples/worley.ts` for quick starts. The `examples` registry exported from `src/index.ts` provides a typed index you can traverse programmatically.
56+
Examples live under `examples/` and can be executed with `tsx`/`ts-node` or compiled for the browser. See `examples/astar.ts`, `examples/flowField.ts`, `examples/navMesh.ts`, `examples/cellularAutomata.ts`, `examples/poissonDisk.ts`, `examples/voronoi.ts`, `examples/diamondSquare.ts`, `examples/lSystem.ts`, `examples/dungeonBsp.ts`, `examples/mazeRecursive.ts`, `examples/mazePrim.ts`, `examples/mazeKruskal.ts`, `examples/mazeWilson.ts`, `examples/mazeAldous.ts`, `examples/mazeDivision.ts`, `examples/steering.ts`, `examples/boids.ts`, `examples/requestDedup.ts`, `examples/deltaTime.ts`, `examples/fixedTimestep.ts`, `examples/camera2D.ts`, `examples/search.ts`, `examples/graph.ts`, `examples/geometry.ts`, `examples/bresenham.ts`, `examples/visual.ts`, `examples/sat.ts`, `examples/simplex.ts`, and `examples/worley.ts` for quick starts. The `examples` registry exported from `src/index.ts` provides a typed index you can traverse programmatically.
5657

5758
## Contributing
5859
1. Fork the repository.

ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
- [x] Fisher–Yates shuffle implementation
5252
- [x] Bresenham line / raster traversal helpers
5353
- Real-time systems:
54-
- [ ] 2D camera system (smooth follow, dead zones, screen shake)
54+
- [x] 2D camera system (smooth follow, dead zones, screen shake)
5555
- [ ] Particle system with configurable emitters
5656
- [ ] Sprite animation controller (frame timing, events)
5757
- [ ] Tween/lerp utility for smooth interpolation

docs/index.d.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,94 @@ export interface FixedTimestepLoop {
919919
*/
920920
export function createFixedTimestepLoop(options: FixedTimestepOptions): FixedTimestepLoop;
921921

922+
// ============================================================================
923+
// 🕹️ GAMEPLAY SYSTEMS
924+
// ============================================================================
925+
926+
/**
927+
* Camera bounds limiting camera travel.
928+
* Use for: constraining view to world dimensions.
929+
* Import: gameplay/camera2D.ts
930+
*/
931+
export interface CameraBounds {
932+
minX: number;
933+
maxX: number;
934+
minY: number;
935+
maxY: number;
936+
}
937+
938+
/**
939+
* Deadzone rectangle keeping targets centred only when they exit the buffer.
940+
* Use for: platformer cameras, cinematic offsets.
941+
* Import: gameplay/camera2D.ts
942+
*/
943+
export interface CameraDeadzone {
944+
width: number;
945+
height: number;
946+
}
947+
948+
/**
949+
* Camera shake configuration.
950+
* Use for: explosions, damage feedback, cinematic moments.
951+
* Import: gameplay/camera2D.ts
952+
*/
953+
export interface CameraShakeOptions {
954+
duration?: number;
955+
magnitude: number;
956+
frequency?: number;
957+
}
958+
959+
/**
960+
* 2D camera configuration options.
961+
* Use for: smooth follow cameras with bounds and dead zones.
962+
* Import: gameplay/camera2D.ts
963+
*/
964+
export interface Camera2DOptions {
965+
viewportWidth: number;
966+
viewportHeight: number;
967+
position?: Point;
968+
bounds?: CameraBounds;
969+
deadzone?: CameraDeadzone;
970+
smoothing?: number;
971+
random?: () => number;
972+
}
973+
974+
/**
975+
* Camera update input.
976+
* Use for: advancing the camera each frame with delta time and target.
977+
* Import: gameplay/camera2D.ts
978+
*/
979+
export interface CameraUpdateOptions {
980+
target: Point;
981+
delta: number;
982+
}
983+
984+
/**
985+
* 2D camera runtime API.
986+
* Use for: retrieving view rects, configuring behaviour, triggering shake.
987+
* Import: gameplay/camera2D.ts
988+
*/
989+
export interface Camera2D {
990+
update(options: CameraUpdateOptions): Rect;
991+
getView(): Rect;
992+
getPosition(): Point;
993+
getCenter(): Point;
994+
setBounds(bounds?: CameraBounds): void;
995+
setDeadzone(deadzone?: CameraDeadzone): void;
996+
setSmoothing(value: number): void;
997+
applyShake(options: CameraShakeOptions): void;
998+
isShaking(): boolean;
999+
reset(position?: Point): void;
1000+
}
1001+
1002+
/**
1003+
* Creates a 2D camera with smoothing, dead zones, and screen shake support.
1004+
* Use for: side-scrollers, top-down games, cinematic sequences.
1005+
* Performance: O(1) per update.
1006+
* Import: gameplay/camera2D.ts
1007+
*/
1008+
export function createCamera2D(options: Camera2DOptions): Camera2D;
1009+
9221010
/**
9231011
* Least recently used cache.
9241012
* Use for: memoizing responses, data loaders, pagination caches.

examples/camera2D.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { createCamera2D } from '../src/index.js';
2+
3+
const camera = createCamera2D({
4+
viewportWidth: 16,
5+
viewportHeight: 9,
6+
deadzone: { width: 4, height: 2 },
7+
smoothing: 0.2,
8+
});
9+
10+
let time = 0;
11+
const target = { x: 0, y: 0 };
12+
13+
for (let i = 0; i < 5; i += 1) {
14+
time += 1 / 60;
15+
target.x = Math.cos(time) * 20;
16+
target.y = Math.sin(time) * 5;
17+
const view = camera.update({ target, delta: 1 / 60 });
18+
console.log(`frame ${i}:`, view);
19+
}
20+
21+
camera.applyShake({ magnitude: 1, duration: 0.3 });
22+
console.log('shake:', camera.update({ target, delta: 1 / 60 }));

0 commit comments

Comments
 (0)