@aethervtt/shard-cards 0.0.0-stage → 0.2.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 +21 -0
- package/README.md +2 -2
- package/dist/collection.d.ts +35 -0
- package/dist/collection.js +114 -0
- package/dist/definition.d.ts +75 -0
- package/dist/definition.js +87 -0
- package/dist/finishes.d.ts +27 -0
- package/dist/finishes.js +79 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +48 -0
- package/dist/mesh.d.ts +4 -0
- package/dist/mesh.js +55 -0
- package/dist/motion.d.ts +12 -0
- package/dist/motion.js +40 -0
- package/dist/plugin.d.ts +13 -0
- package/dist/plugin.js +107 -0
- package/dist/shader.d.ts +2 -0
- package/dist/shader.js +145 -0
- package/dist/table.d.ts +124 -0
- package/dist/table.js +537 -0
- package/dist/textures.d.ts +17 -0
- package/dist/textures.js +53 -0
- package/package.json +39 -4
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { defineSystem, ShardError, t, Update } from "@aethervtt/shard-core";
|
|
2
|
+
import {
|
|
3
|
+
addRenderFeatures,
|
|
4
|
+
defineMaterial,
|
|
5
|
+
Gpu,
|
|
6
|
+
registerShaders,
|
|
7
|
+
Shaders
|
|
8
|
+
} from "@aethervtt/shard-render";
|
|
9
|
+
import { definePlugin, Time } from "@aethervtt/shard-runtime";
|
|
10
|
+
import { Card, CardDefinition, CardInteraction, CardTilt } from "./definition.js";
|
|
11
|
+
import { builtinCardFinishes } from "./finishes.js";
|
|
12
|
+
import { cardShader } from "./shader.js";
|
|
13
|
+
import { Cards, CardTableState } from "./table.js";
|
|
14
|
+
const updateCards = defineSystem({
|
|
15
|
+
name: "cards/update",
|
|
16
|
+
run: (_, world) => {
|
|
17
|
+
const time = world.resource(Time);
|
|
18
|
+
world.resource(Cards).update(time.delta, time.elapsed);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
function cardsPlugin(options) {
|
|
22
|
+
const finishes = [...builtinCardFinishes(), ...options.finishes ?? []];
|
|
23
|
+
if (new Set(finishes.map((f) => f.name)).size !== finishes.length) {
|
|
24
|
+
throw new ShardError(
|
|
25
|
+
"cards/duplicate-finish",
|
|
26
|
+
"Finish names must be unique within a card table"
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const lighting = options.lighting ?? "pbr";
|
|
30
|
+
let hash = 2166136261;
|
|
31
|
+
const signature = JSON.stringify([
|
|
32
|
+
lighting,
|
|
33
|
+
finishes.map((f) => [f.name, f.options.surface, f.options.response, f.keys])
|
|
34
|
+
]);
|
|
35
|
+
for (let i = 0; i < signature.length; i++)
|
|
36
|
+
hash = Math.imul(hash ^ signature.charCodeAt(i), 16777619);
|
|
37
|
+
const suffix = (hash >>> 0).toString(16);
|
|
38
|
+
const name = `CardSurface${suffix}`;
|
|
39
|
+
return definePlugin({
|
|
40
|
+
name: "cards",
|
|
41
|
+
dependencies: ["render/forward"],
|
|
42
|
+
provides: [Card, CardDefinition, CardInteraction, CardTilt, Cards],
|
|
43
|
+
build(app) {
|
|
44
|
+
app.world.initResource(CardDefinition.store);
|
|
45
|
+
addRenderFeatures(app.world, {
|
|
46
|
+
name: "cards/finishes",
|
|
47
|
+
description: "Instanced two-sided cards with independently masked foil finishes.",
|
|
48
|
+
nodes: [],
|
|
49
|
+
baseline: {
|
|
50
|
+
strategy: "Texture arrays and texture-backed instance records in the shared forward path."
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
app.addSystems(Update, updateCards);
|
|
54
|
+
},
|
|
55
|
+
ready(app) {
|
|
56
|
+
const baseline = app.world.resource(Gpu).tier === "baseline";
|
|
57
|
+
const shaderFinishes = baseline ? finishes.map(
|
|
58
|
+
(f) => f.options.baseline === "unsupported" ? {
|
|
59
|
+
...f,
|
|
60
|
+
options: { ...f.options, surface: "return base;", response: "return current;" }
|
|
61
|
+
} : f
|
|
62
|
+
) : finishes;
|
|
63
|
+
const type = defineMaterial(`cards/${name}`, {
|
|
64
|
+
extends: lighting === "pbr" ? "standard" : "none",
|
|
65
|
+
// Card art/finish arrays supply the surface; unused standard texture slots cost no bindings.
|
|
66
|
+
standardTextures: false,
|
|
67
|
+
blend: "opaque",
|
|
68
|
+
shader: `cards::surface_${suffix}`,
|
|
69
|
+
plugin: "cards",
|
|
70
|
+
fields: {
|
|
71
|
+
art: t.handle("Texture"),
|
|
72
|
+
masks: t.handle("Texture"),
|
|
73
|
+
records: t.handle("Texture"),
|
|
74
|
+
luminance: t.f32({ default: 1.2 }),
|
|
75
|
+
gloss: t.f32({ default: 0.35 }),
|
|
76
|
+
maskView: t.f32(),
|
|
77
|
+
clock: t.f32(),
|
|
78
|
+
automaticClock: t.f32(),
|
|
79
|
+
light: t.vec4({ default: [-0.4, 0.6, 1, 0] })
|
|
80
|
+
},
|
|
81
|
+
arrays: ["art", "masks"],
|
|
82
|
+
colors: ["art"]
|
|
83
|
+
});
|
|
84
|
+
registerShaders(app.world.resource(Shaders), {
|
|
85
|
+
[`cards::surface_${suffix}`]: cardShader(shaderFinishes, type.modulePath, name, lighting)
|
|
86
|
+
});
|
|
87
|
+
app.world.insertResource(
|
|
88
|
+
Cards,
|
|
89
|
+
new CardTableState(
|
|
90
|
+
app.world,
|
|
91
|
+
finishes,
|
|
92
|
+
type,
|
|
93
|
+
options.art,
|
|
94
|
+
options.masks,
|
|
95
|
+
options.capacity,
|
|
96
|
+
options.textureBudgetMiB
|
|
97
|
+
)
|
|
98
|
+
);
|
|
99
|
+
},
|
|
100
|
+
dispose(app) {
|
|
101
|
+
app.world.tryResource(Cards)?.dispose();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
export {
|
|
106
|
+
cardsPlugin
|
|
107
|
+
};
|
package/dist/shader.d.ts
ADDED
package/dist/shader.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { CARD_MOTION_WGSL } from "./motion.js";
|
|
2
|
+
function cardShader(finishes, module, uniform, lighting) {
|
|
3
|
+
const bodies = finishes.map(
|
|
4
|
+
(f, i) => `fn finish_${i + 1}(ctx: CardFinishContext, base: vec3f) -> vec3f { ${f.options.surface} }`
|
|
5
|
+
).join("\n");
|
|
6
|
+
const cases = finishes.map((_, i) => `case ${i + 1}u: { return finish_${i + 1}(ctx, base); }`).join("\n");
|
|
7
|
+
const responses = finishes.map(
|
|
8
|
+
(f, i) => `fn response_${i + 1}(ctx: CardFinishContext, current: vec2f) -> vec2f { ${f.options.response ?? "return vec2f(0.35, 0.28);"} }`
|
|
9
|
+
).join("\n");
|
|
10
|
+
const responseCases = finishes.map((_, i) => `case ${i + 1}u: { return response_${i + 1}(ctx, current); }`).join("\n");
|
|
11
|
+
return `
|
|
12
|
+
import shard::pbr::types::{ VertexOutput, PbrInput };
|
|
13
|
+
${lighting === "pbr" ? "import shard::pbr::standard::material;" : ""}
|
|
14
|
+
import shard::view::view;
|
|
15
|
+
import shard::mesh::vertex_instance_data;
|
|
16
|
+
import ${module}::{ ${uniform}, ${uniform}_art, ${uniform}_art_sampler, ${uniform}_masks, ${uniform}_masks_sampler, ${uniform}_records };
|
|
17
|
+
|
|
18
|
+
struct CardFinishContext {
|
|
19
|
+
uv: vec2f, art_uv: vec2f, footprint: vec2f,
|
|
20
|
+
normal: vec3f, view: vec3f, light: vec3f,
|
|
21
|
+
shift: vec2f, pointer: vec2f, params: vec4f,
|
|
22
|
+
facing: f32, grazing: f32, glare: f32, seed: f32, time: f32,
|
|
23
|
+
}
|
|
24
|
+
fn card_spectrum(t: f32) -> vec3f {
|
|
25
|
+
return 0.5 + 0.5 * cos(6.2831853 * (vec3f(t) + vec3f(0.0, 0.33, 0.67)));
|
|
26
|
+
}
|
|
27
|
+
fn card_hash(p: vec2f) -> f32 {
|
|
28
|
+
return fract(sin(dot(p, vec2f(127.1, 311.7))) * 43758.5453);
|
|
29
|
+
}
|
|
30
|
+
${CARD_MOTION_WGSL}
|
|
31
|
+
${bodies}
|
|
32
|
+
${responses}
|
|
33
|
+
struct CardSurface { color: vec3f, response: vec2f }
|
|
34
|
+
fn card_response(kind: u32, ctx: CardFinishContext, current: vec2f) -> vec2f {
|
|
35
|
+
switch kind { ${responseCases} default: { return current; } }
|
|
36
|
+
}
|
|
37
|
+
fn card_finish(kind: u32, ctx: CardFinishContext, base: vec3f) -> vec3f {
|
|
38
|
+
switch kind { ${cases} default: { return base; } }
|
|
39
|
+
}
|
|
40
|
+
fn record(slot: i32, field: i32) -> vec4f {
|
|
41
|
+
return textureLoad(${uniform}_records, vec2i(field, slot), 0);
|
|
42
|
+
}
|
|
43
|
+
override fn vertex_extra(position: vec3f, normal: vec3f, uv: vec2f) -> vec4f {
|
|
44
|
+
return vec4f(vertex_instance_data(), 0.0, 0.0);
|
|
45
|
+
}
|
|
46
|
+
fn card_surface(in: VertexOutput) -> CardSurface {
|
|
47
|
+
let uvDx = dpdx(in.uv);
|
|
48
|
+
let uvDy = dpdy(in.uv);
|
|
49
|
+
let slot = i32(round(in.extra.x));
|
|
50
|
+
let side = i32(round(in.uv1.x));
|
|
51
|
+
let cardData = record(slot, 0);
|
|
52
|
+
let edge = record(slot, 1);
|
|
53
|
+
if (side == 2) { return CardSurface(edge.rgb, vec2f(0.0, 0.85)); }
|
|
54
|
+
let start = 4 + side * 20;
|
|
55
|
+
let face = record(slot, start);
|
|
56
|
+
let crop = record(slot, start + 1);
|
|
57
|
+
let background = record(slot, start + 2);
|
|
58
|
+
let controls = record(slot, 2);
|
|
59
|
+
let motion = record(slot, 3);
|
|
60
|
+
var pointer = controls.xy * controls.z;
|
|
61
|
+
if (motion.x > 0.5) {
|
|
62
|
+
pointer = card_motion(${uniform}.automaticClock, motion.y, motion.z, motion.w);
|
|
63
|
+
}
|
|
64
|
+
var uv = in.uv;
|
|
65
|
+
var fitDx = uvDx;
|
|
66
|
+
var fitDy = uvDy;
|
|
67
|
+
let turns = u32(face.w);
|
|
68
|
+
if (turns == 1u) { uv = vec2f(uv.y, 1.0 - uv.x); fitDx = vec2f(uvDx.y, -uvDx.x); fitDy = vec2f(uvDy.y, -uvDy.x); }
|
|
69
|
+
if (turns == 2u) { uv = vec2f(1.0) - uv; fitDx = -uvDx; fitDy = -uvDy; }
|
|
70
|
+
if (turns == 3u) { uv = vec2f(1.0 - uv.y, uv.x); fitDx = vec2f(-uvDx.y, uvDx.x); fitDy = vec2f(-uvDy.y, uvDy.x); }
|
|
71
|
+
var fitted = uv;
|
|
72
|
+
var faceAspect = cardData.z;
|
|
73
|
+
if (turns == 1u || turns == 3u) { faceAspect = 1.0 / faceAspect; }
|
|
74
|
+
let ratio = face.z * crop.z / max(crop.w, 0.001) / faceAspect;
|
|
75
|
+
if (face.y < 1.5) {
|
|
76
|
+
let cover = face.y > 0.5;
|
|
77
|
+
if ((ratio > 1.0) != cover) { fitted.y = (uv.y - 0.5) * ratio + 0.5; fitDx.y *= ratio; fitDy.y *= ratio; }
|
|
78
|
+
else { fitted.x = (uv.x - 0.5) / max(ratio, 0.001) + 0.5; fitDx.x /= max(ratio, 0.001); fitDy.x /= max(ratio, 0.001); }
|
|
79
|
+
}
|
|
80
|
+
let inside = all(fitted >= vec2f(0.0)) && all(fitted <= vec2f(1.0));
|
|
81
|
+
let artUV = crop.xy + clamp(fitted, vec2f(0.0), vec2f(1.0)) * crop.zw;
|
|
82
|
+
let art = textureSampleGrad(${uniform}_art, ${uniform}_art_sampler, artUV, i32(face.x), fitDx * crop.zw, fitDy * crop.zw);
|
|
83
|
+
var base = background.rgb;
|
|
84
|
+
if (inside && face.x > 0.0) { base = mix(base, art.rgb, art.a); }
|
|
85
|
+
let n = normalize(in.world_normal);
|
|
86
|
+
let v = normalize(view.cameraPosition - in.world_position);
|
|
87
|
+
var light = normalize(${uniform}.light.xyz);
|
|
88
|
+
if (motion.x > 0.5) {
|
|
89
|
+
light = normalize(light + vec3f(pointer.x, -pointer.y, 0.0) * 0.85);
|
|
90
|
+
}
|
|
91
|
+
let facing = max(0.0, dot(n, v));
|
|
92
|
+
let grazing = pow(1.0 - facing, 2.0);
|
|
93
|
+
let shift = n.xy * 2.7 + v.xy * 0.8 + pointer * select(0.3, 0.8, motion.x > 0.5) + light.xy * 0.6;
|
|
94
|
+
let glare = pow(max(0.0, dot(n, normalize(v + light))), 24.0);
|
|
95
|
+
var ctx = CardFinishContext(in.uv, artUV, abs(uvDx) + abs(uvDy), n, v, light, shift,
|
|
96
|
+
pointer, vec4f(0.0), facing, grazing, glare, cardData.w, ${uniform}.clock);
|
|
97
|
+
var response = vec2f(0.0, mix(0.85, 0.18, ${uniform}.gloss));
|
|
98
|
+
for (var i = 0; i < 4; i++) {
|
|
99
|
+
let layer = record(slot, start + 3 + i * 4);
|
|
100
|
+
let params = record(slot, start + 4 + i * 4);
|
|
101
|
+
let transform = record(slot, start + 5 + i * 4);
|
|
102
|
+
let flags = record(slot, start + 6 + i * 4);
|
|
103
|
+
var maskUV = in.uv;
|
|
104
|
+
var maskDx = uvDx;
|
|
105
|
+
var maskDy = uvDy;
|
|
106
|
+
if (flags.z > 0.5) { maskUV = artUV; maskDx = fitDx * crop.zw; maskDy = fitDy * crop.zw; }
|
|
107
|
+
maskUV = maskUV * transform.xy + transform.zw;
|
|
108
|
+
let rgba = textureSampleGrad(${uniform}_masks, ${uniform}_masks_sampler, maskUV, i32(layer.z), maskDx * transform.xy, maskDy * transform.xy);
|
|
109
|
+
var maskValue = rgba[u32(flags.x)];
|
|
110
|
+
if (flags.y > 0.5) { maskValue = 1.0 - maskValue; }
|
|
111
|
+
if (flags.z > 0.5 && !inside) { maskValue = 0.0; }
|
|
112
|
+
let coverage = clamp(maskValue * layer.y * cardData.x, 0.0, 1.0);
|
|
113
|
+
if (${uniform}.maskView > 0.5 && i == i32(${uniform}.maskView) - 1) {
|
|
114
|
+
return CardSurface(vec3f(maskValue), vec2f(0.0, 1.0));
|
|
115
|
+
}
|
|
116
|
+
ctx.params = params;
|
|
117
|
+
let result = card_finish(u32(layer.x), ctx, base);
|
|
118
|
+
base = mix(base, result, coverage);
|
|
119
|
+
let nextResponse = card_response(u32(layer.x), ctx, response);
|
|
120
|
+
response = mix(response, clamp(nextResponse, vec2f(0.0, 0.045), vec2f(1.0)), coverage);
|
|
121
|
+
}
|
|
122
|
+
${lighting === "unlit" ? `base += vec3f(glare * ${uniform}.gloss * 0.12);` : ""}
|
|
123
|
+
return CardSurface(base, response);
|
|
124
|
+
}
|
|
125
|
+
${lighting === "pbr" ? `
|
|
126
|
+
override fn pbr_input(in: VertexOutput) -> PbrInput {
|
|
127
|
+
let surface = card_surface(in);
|
|
128
|
+
var p: PbrInput;
|
|
129
|
+
p.base_color = clamp(surface.color * material.baseColor.rgb, vec3f(0.0), vec3f(1.0));
|
|
130
|
+
p.alpha = 1.0;
|
|
131
|
+
p.normal = normalize(in.world_normal);
|
|
132
|
+
p.metallic = surface.response.x;
|
|
133
|
+
p.roughness = surface.response.y;
|
|
134
|
+
p.emissive = vec3f(0.0);
|
|
135
|
+
p.occlusion = 1.0;
|
|
136
|
+
return p;
|
|
137
|
+
}` : `
|
|
138
|
+
override fn shade(in: VertexOutput) -> vec4f {
|
|
139
|
+
return vec4f(max(card_surface(in).color, vec3f(0.0)) * ${uniform}.luminance, 1.0);
|
|
140
|
+
}`}
|
|
141
|
+
`;
|
|
142
|
+
}
|
|
143
|
+
export {
|
|
144
|
+
cardShader
|
|
145
|
+
};
|
package/dist/table.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { type AssetRef, type Entity, type World } from '@aethervtt/shard-core';
|
|
2
|
+
import { MaterialAsset, type MaterialType } from '@aethervtt/shard-render';
|
|
3
|
+
import { Texture } from '@aethervtt/shard-texture';
|
|
4
|
+
import { type CardDefinitionValue } from './definition.js';
|
|
5
|
+
import type { CardFinish } from './finishes.js';
|
|
6
|
+
import { type CardAutomaticMotionValue } from './motion.js';
|
|
7
|
+
import type { CardTexturePage } from './textures.js';
|
|
8
|
+
export interface CardPose {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
z: number;
|
|
12
|
+
pitch?: number;
|
|
13
|
+
yaw?: number;
|
|
14
|
+
roll?: number;
|
|
15
|
+
scale?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface CardHit {
|
|
18
|
+
card: CardHandle | undefined;
|
|
19
|
+
side: 'front' | 'back' | 'edge';
|
|
20
|
+
u: number;
|
|
21
|
+
v: number;
|
|
22
|
+
distance: number;
|
|
23
|
+
}
|
|
24
|
+
export declare const createCardHit: () => CardHit;
|
|
25
|
+
export declare class CardHandle {
|
|
26
|
+
readonly slot: number;
|
|
27
|
+
readonly entity: Entity;
|
|
28
|
+
readonly instanceId: string;
|
|
29
|
+
readonly definition: CardDefinitionValue;
|
|
30
|
+
readonly table: CardTableState;
|
|
31
|
+
readonly pose: Float64Array<ArrayBuffer>;
|
|
32
|
+
readonly target: Float64Array<ArrayBuffer>;
|
|
33
|
+
readonly start: Float64Array<ArrayBuffer>;
|
|
34
|
+
readonly translation: [number, number, number];
|
|
35
|
+
readonly rotation: [number, number, number, number];
|
|
36
|
+
readonly scale: [number, number, number];
|
|
37
|
+
readonly transform: {
|
|
38
|
+
translation: [number, number, number];
|
|
39
|
+
rotation: [number, number, number, number];
|
|
40
|
+
scale: [number, number, number];
|
|
41
|
+
};
|
|
42
|
+
readonly data: Float32Array;
|
|
43
|
+
readonly bytes: Uint8Array<ArrayBuffer>;
|
|
44
|
+
readonly halfView: DataView;
|
|
45
|
+
active: boolean;
|
|
46
|
+
interactive: boolean;
|
|
47
|
+
tilt: boolean;
|
|
48
|
+
automaticTilt: boolean;
|
|
49
|
+
maxTilt: number;
|
|
50
|
+
hoverX: number;
|
|
51
|
+
hoverY: number;
|
|
52
|
+
hovered: boolean;
|
|
53
|
+
tiltX: number;
|
|
54
|
+
tiltY: number;
|
|
55
|
+
duration: number;
|
|
56
|
+
age: number;
|
|
57
|
+
poseDirty: boolean;
|
|
58
|
+
dataDirty: boolean;
|
|
59
|
+
animationFps: number;
|
|
60
|
+
constructor(table: CardTableState, slot: number, entity: Entity, id: string, definition: CardDefinitionValue);
|
|
61
|
+
setPose(pose: CardPose, seconds?: number): void;
|
|
62
|
+
flip(seconds?: number): void;
|
|
63
|
+
setHover(u: number, v: number, active: boolean): void;
|
|
64
|
+
/** Replaces the automatic driver settings; no per-frame instance uploads for foil-only motion. */
|
|
65
|
+
setAutomaticMotion(options: Partial<CardAutomaticMotionValue>): void;
|
|
66
|
+
setStrength(value: number, layer?: number, side?: 'front' | 'back'): void;
|
|
67
|
+
setFinish(layer: number, name: string, parameters?: Record<string, unknown>, side?: 'front' | 'back'): void;
|
|
68
|
+
dispose(): void;
|
|
69
|
+
}
|
|
70
|
+
export declare class CardTableState {
|
|
71
|
+
readonly world: World;
|
|
72
|
+
readonly finishes: readonly CardFinish[];
|
|
73
|
+
readonly cards: (CardHandle | undefined)[];
|
|
74
|
+
readonly recordBytes: Uint8Array<ArrayBuffer>;
|
|
75
|
+
readonly records: Texture;
|
|
76
|
+
readonly material: MaterialAsset;
|
|
77
|
+
readonly materialRef: AssetRef<'Material'>;
|
|
78
|
+
readonly art: CardTexturePage;
|
|
79
|
+
readonly masks: CardTexturePage;
|
|
80
|
+
readonly capacity: number;
|
|
81
|
+
readonly byId: Map<string, CardHandle>;
|
|
82
|
+
private readonly definitionRefs;
|
|
83
|
+
private readonly meshes;
|
|
84
|
+
private readonly free;
|
|
85
|
+
private readonly textureRefs;
|
|
86
|
+
private readonly dirtyOrigin;
|
|
87
|
+
private readonly writeTarget;
|
|
88
|
+
private readonly writeLayout;
|
|
89
|
+
private readonly writeSize;
|
|
90
|
+
private disposed;
|
|
91
|
+
private automaticTime;
|
|
92
|
+
private readonly automaticPoint;
|
|
93
|
+
reducedMotion: boolean;
|
|
94
|
+
animated: boolean;
|
|
95
|
+
uploadedBytes: number;
|
|
96
|
+
constructor(world: World, finishes: readonly CardFinish[], type: MaterialType, art: CardTexturePage, masks: CardTexturePage, capacity?: number, budgetMiB?: number);
|
|
97
|
+
wake(): void;
|
|
98
|
+
spawn(definition: CardDefinitionValue, instanceId: string, pose?: CardPose): CardHandle;
|
|
99
|
+
private face;
|
|
100
|
+
finish(card: CardHandle, layer: number, name: string, parameters: Record<string, unknown>, side: 'front' | 'back'): void;
|
|
101
|
+
configure(values: {
|
|
102
|
+
maskView?: number;
|
|
103
|
+
gloss?: number;
|
|
104
|
+
luminance?: number;
|
|
105
|
+
light?: readonly number[];
|
|
106
|
+
}): void;
|
|
107
|
+
update(delta: number, elapsed: number): void;
|
|
108
|
+
private flush;
|
|
109
|
+
remove(card: CardHandle): void;
|
|
110
|
+
describe(): {
|
|
111
|
+
cards: number;
|
|
112
|
+
capacity: number;
|
|
113
|
+
finishes: string[];
|
|
114
|
+
textureBytes: number;
|
|
115
|
+
uploadedBytes: number;
|
|
116
|
+
reducedMotion: boolean;
|
|
117
|
+
};
|
|
118
|
+
dispose(): void;
|
|
119
|
+
}
|
|
120
|
+
export declare const Cards: import("@aethervtt/shard-core").ResourceDef<CardTableState>;
|
|
121
|
+
/** Project against the authored pose, excluding hover tilt, to prevent pointer feedback. */
|
|
122
|
+
export declare function cardTiltCoordinates(card: CardHandle, origin: ArrayLike<number>, direction: ArrayLike<number>, out: Float64Array): boolean;
|
|
123
|
+
/** Camera-independent exact rounded face query; writes into caller-owned storage. */
|
|
124
|
+
export declare function hitCards(table: CardTableState, origin: ArrayLike<number>, direction: ArrayLike<number>, out: CardHit): boolean;
|