@aethervtt/shard-transform 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Patrick Dias
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @aethervtt/shard-transform
2
+
3
+ Part of [Shard](https://github.com/aethervtt/shard), a WebGPU-first 2D/3D game engine in TypeScript. See the repository for documentation.
@@ -0,0 +1,10 @@
1
+ import { type Infer } from '@aethervtt/shard-core';
2
+ export declare const GlobalTransform: import("@aethervtt/shard-core").ComponentDef<{
3
+ readonly matrix: import("@aethervtt/shard-core").FieldType<[number, number, number, number, number, number, number, number, number, number, number, number], "f32">;
4
+ }>;
5
+ export declare const Transform: import("@aethervtt/shard-core").ComponentDef<{
6
+ readonly translation: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec3, "f32">;
7
+ readonly rotation: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Quat, "f32">;
8
+ readonly scale: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec3, "f32">;
9
+ }>;
10
+ export type TransformValue = Infer<typeof Transform>;
@@ -0,0 +1,30 @@
1
+ import { defineComponent, t } from "@aethervtt/shard-core";
2
+ const GlobalTransform = defineComponent(
3
+ "core/GlobalTransform",
4
+ {
5
+ matrix: t.affine3x4({
6
+ readonly: true,
7
+ description: "World matrix (top three rows, row by row), relative to the floating origin. Computed from Transform each frame."
8
+ })
9
+ },
10
+ {
11
+ description: "World-space transform relative to the floating origin (the world origin when there is none). Computed by core/transform-propagate; do not write.",
12
+ serialize: false
13
+ }
14
+ );
15
+ const Transform = defineComponent(
16
+ "core/Transform",
17
+ {
18
+ translation: t.vec3({ unit: "m", description: "Position relative to the parent (or world)." }),
19
+ rotation: t.quat({ description: "Rotation relative to the parent, as a unit quaternion." }),
20
+ scale: t.vec3({ default: [1, 1, 1], description: "Scale along local axes." })
21
+ },
22
+ {
23
+ description: "Local transform. Y is up, -Z is forward. In 2D, translation.z orders layers and rotation is around Z.",
24
+ requires: [GlobalTransform]
25
+ }
26
+ );
27
+ export {
28
+ GlobalTransform,
29
+ Transform
30
+ };
package/dist/grid.d.ts ADDED
@@ -0,0 +1,124 @@
1
+ import { type Entity, type Table, type World } from '@aethervtt/shard-core';
2
+ /**
3
+ * Large-world coordinates (spec 0040). A position in a grid is `GridCell × cellSize + translation`:
4
+ * the cell is an exact integer, and the f32 translation stays small. `GlobalTransform` is relative
5
+ * to the `FloatingOrigin` entity's cell, so everything near the camera is precise.
6
+ */
7
+ export declare const Grid: import("@aethervtt/shard-core").ComponentDef<{
8
+ readonly cellSize: import("@aethervtt/shard-core").FieldType<number, "f64">;
9
+ readonly hysteresis: import("@aethervtt/shard-core").FieldType<number, "f32">;
10
+ }>;
11
+ export declare const GridCell: import("@aethervtt/shard-core").ComponentDef<{
12
+ readonly cell: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").IVec3, "i32">;
13
+ }>;
14
+ export declare const FloatingOrigin: import("@aethervtt/shard-core").TagDef;
15
+ export interface OriginShiftData {
16
+ /** The origin grid after the shift (null for the root frame). */
17
+ grid: Entity | null;
18
+ /** oldCell − newCell, when the origin stayed in the same grid; zero when it changed grids. */
19
+ delta: [number, number, number];
20
+ /** Metres to add to a position in the old origin frame to get it in the new one. */
21
+ offset: [number, number, number];
22
+ }
23
+ /**
24
+ * Sent (and triggered for observers) when the origin frame moves: the origin entity changed cells or
25
+ * grids. Anything that keeps positions from `GlobalTransform` across frames adds `offset` to them.
26
+ */
27
+ export declare const OriginShift: import("@aethervtt/shard-core").EventDef<OriginShiftData>;
28
+ /**
29
+ * Each grid's frame relative to the origin: `origin = A · ((cell − ref) × cellSize + p)` for a point
30
+ * `p` in cell `cell`. `ref` is a cell near the origin, so the cell difference is exact integer math
31
+ * and `A`'s translation stays small. Slot 0 is the root frame (entities with no grid ancestor).
32
+ */
33
+ export declare class GridFrames {
34
+ /** Grid entity per slot (ROOT for slot 0). */
35
+ entity: Entity[];
36
+ /** f64 affine per slot (12 each). */
37
+ a: Float64Array<ArrayBuffer>;
38
+ /** Reference cell per slot (3 each). */
39
+ ref: Int32Array<ArrayBuffer>;
40
+ cellSize: Float64Array<ArrayBuffer>;
41
+ /** The grid's own frame → origin, rounded to f32 (its GlobalTransform). */
42
+ frame32: Float32Array<ArrayBuffer>;
43
+ /** 1 when the slot's A or ref changed this frame: everything under it re-propagates. */
44
+ moved: Uint8Array<ArrayBuffer>;
45
+ /** Solve stamp per slot; a slot is current when it equals `stamp`. */
46
+ solved: Uint32Array<ArrayBuffer>;
47
+ /** Seen stamp per slot, to drop slots of despawned grids. */
48
+ seen: Uint32Array<ArrayBuffer>;
49
+ count: number;
50
+ stamp: number;
51
+ readonly slotOf: Map<number, number>;
52
+ /** Origin grid slot and cell. */
53
+ originSlot: number;
54
+ originCell: Int32Array<ArrayBuffer>;
55
+ originEntity: Entity;
56
+ /** Whether any grid or origin is active; false means the root frame is the identity. */
57
+ active: boolean;
58
+ /** True when slot 0 (root frame) is exactly the identity. */
59
+ rootIdentity: boolean;
60
+ /**
61
+ * Some grid sits under an ordinary entity, whose transform change detection can't see cheaply,
62
+ * so every frame solves in full.
63
+ */
64
+ indirect: boolean;
65
+ constructor();
66
+ slot(grid: Entity): number;
67
+ private grow;
68
+ /** Drops slots whose grid no longer exists. Rare: only when grids despawn. */
69
+ compact(): void;
70
+ }
71
+ /** The grid frames the propagation system solved this frame. Read by physics and the renderer. */
72
+ export declare const GridFramesResource: import("@aethervtt/shard-core").ResourceDef<GridFrames>;
73
+ /** Where an entity sits: the grid it's in (ROOT for none), its cell there, and the f64 affine
74
+ * from the entity's frame to `cell × cellSize` in that grid. */
75
+ export interface Placement {
76
+ grid: Entity;
77
+ cell: Int32Array;
78
+ m: Float64Array;
79
+ /** How many entities' transforms were composed (1 for a direct child of the grid). */
80
+ depth: number;
81
+ }
82
+ export declare const createPlacement: () => Placement;
83
+ export declare function isGrid(world: World, e: Entity): boolean;
84
+ /**
85
+ * Walks up from `e` (including its own transform when `self` is true) to its nearest grid, composing
86
+ * transforms in f64. The direct child of that grid contributes its cell.
87
+ */
88
+ export declare function placementOf(world: World, e: Entity, out: Placement, self?: boolean): Placement;
89
+ /**
90
+ * Solves every grid's frame for this frame. `gridTables` are the tables holding grids (from the
91
+ * propagation system's query); `origin` is the FloatingOrigin entity or ROOT. Returns whether the
92
+ * origin frame shifted, with the shift written into `shift`. When nothing that affects the frames
93
+ * changed since `since` (pass -1 to force), it only checks the origin's cell.
94
+ */
95
+ export declare function solveGrids(world: World, frames: GridFrames, gridTables: readonly Table[], origin: Entity, shift: OriginShiftData, since?: number): boolean;
96
+ /** Back to "no grids": the root frame is the identity. Returns whether anything changed. */
97
+ export declare function resetGrids(frames: GridFrames): boolean;
98
+ /**
99
+ * The f64 affine from `e`'s own frame to the origin frame (its exact GlobalTransform). Solves grids
100
+ * fresh, so it's valid right after spawning or moving things. Cold path.
101
+ */
102
+ export declare function originMatrix64(world: World, e: Entity, out: Float64Array): Float64Array;
103
+ /**
104
+ * Position of `e` in `frame`'s coordinates (default: the origin frame), exact to f64. With a grid
105
+ * as `frame`, the result is `cell × cellSize + offset` in that grid.
106
+ */
107
+ export declare function worldPosition64(world: World, e: Entity, out: Float64Array, frame?: Entity): Float64Array;
108
+ /**
109
+ * Distance between two entities, exact at any distance from the origin: entities in the same grid
110
+ * subtract cells as integers first.
111
+ */
112
+ export declare function distance64(world: World, a: Entity, b: Entity): number;
113
+ /**
114
+ * Puts `e` at `position` (f64, in `grid`'s frame) as a direct child of `grid`: sets its cell,
115
+ * translation, and parent.
116
+ */
117
+ export declare function placeInGrid(world: World, e: Entity, grid: Entity, position: ArrayLike<number>): void;
118
+ /**
119
+ * Moves `e` into `grid` (as a direct child) keeping its pose in the origin frame, e.g. a ship
120
+ * entering a planet's rotating grid. Computes the new cell and transform in f64.
121
+ */
122
+ export declare function reparentToGrid(world: World, e: Entity, grid: Entity): void;
123
+ /** The grid `e` is directly in (its parent, when that's a Grid), or undefined. */
124
+ export declare function gridOf(world: World, e: Entity): Entity | undefined;