@aethervtt/shard-dice 0.0.0-stage → 0.2.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.
- package/LICENSE +21 -0
- package/README.md +2 -2
- package/dist/attachments.d.ts +79 -0
- package/dist/attachments.js +43 -0
- package/dist/audio.d.ts +19 -0
- package/dist/audio.js +187 -0
- package/dist/builtins.d.ts +25 -0
- package/dist/builtins.js +335 -0
- package/dist/cells.d.ts +33 -0
- package/dist/cells.js +53 -0
- package/dist/components.d.ts +14 -0
- package/dist/components.js +27 -0
- package/dist/definition-asset.d.ts +19 -0
- package/dist/definition-asset.js +60 -0
- package/dist/definition.d.ts +98 -0
- package/dist/definition.js +320 -0
- package/dist/dice-worker.d.ts +1 -0
- package/dist/dice-worker.js +3 -0
- package/dist/effects.d.ts +99 -0
- package/dist/effects.js +200 -0
- package/dist/entrances.d.ts +48 -0
- package/dist/entrances.js +54 -0
- package/dist/families.d.ts +17 -0
- package/dist/families.js +131 -0
- package/dist/glyphs.d.ts +29 -0
- package/dist/glyphs.js +270 -0
- package/dist/golden.json +17 -0
- package/dist/hull.d.ts +32 -0
- package/dist/hull.js +154 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +324 -0
- package/dist/landing.d.ts +29 -0
- package/dist/landing.js +93 -0
- package/dist/layout.d.ts +75 -0
- package/dist/layout.js +137 -0
- package/dist/marks.d.ts +54 -0
- package/dist/marks.js +543 -0
- package/dist/material.d.ts +80 -0
- package/dist/material.js +343 -0
- package/dist/math.d.ts +39 -0
- package/dist/math.js +136 -0
- package/dist/mesh.d.ts +9 -0
- package/dist/mesh.js +105 -0
- package/dist/methods.d.ts +2 -0
- package/dist/methods.js +42 -0
- package/dist/numerals.d.ts +9 -0
- package/dist/numerals.js +47 -0
- package/dist/plugin.d.ts +41 -0
- package/dist/plugin.js +176 -0
- package/dist/preview.d.ts +32 -0
- package/dist/preview.js +135 -0
- package/dist/quality.d.ts +12 -0
- package/dist/quality.js +18 -0
- package/dist/resources.d.ts +85 -0
- package/dist/resources.js +191 -0
- package/dist/roll.d.ts +68 -0
- package/dist/roll.js +97 -0
- package/dist/settle.d.ts +53 -0
- package/dist/settle.js +96 -0
- package/dist/skin.d.ts +64 -0
- package/dist/skin.js +313 -0
- package/dist/sound.d.ts +33 -0
- package/dist/sound.js +296 -0
- package/dist/studio.d.ts +3 -0
- package/dist/studio.js +48 -0
- package/dist/table.d.ts +227 -0
- package/dist/table.js +1818 -0
- package/dist/test-worker.d.ts +1 -0
- package/dist/test-worker.js +12 -0
- package/dist/track.d.ts +70 -0
- package/dist/track.js +304 -0
- package/dist/tray.d.ts +2 -0
- package/dist/tray.js +43 -0
- package/dist/variants.d.ts +9 -0
- package/dist/variants.js +46 -0
- package/dist/windows.d.ts +25 -0
- package/dist/windows.js +77 -0
- package/dist/worker.d.ts +6 -0
- package/dist/worker.js +9 -0
- package/package.json +47 -4
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type AssetRef, type FieldValue, type Infer, ShardError } from '@aethervtt/shard-core';
|
|
2
|
+
import { type DieDefinition } from './definition.js';
|
|
3
|
+
export declare const FaceMarkSchema: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").InferFields<{
|
|
4
|
+
kind: import("@aethervtt/shard-core").FieldType<"blank" | "glyph" | "pips" | "text", "u8">;
|
|
5
|
+
text: import("@aethervtt/shard-core").FieldType<string, "object">;
|
|
6
|
+
font: import("@aethervtt/shard-core").FieldType<AssetRef<"Font"> | null, "object">;
|
|
7
|
+
size: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
8
|
+
weight: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
9
|
+
underline: import("@aethervtt/shard-core").FieldType<"always" | "auto" | "never", "u8">;
|
|
10
|
+
count: import("@aethervtt/shard-core").FieldType<number, "u8">;
|
|
11
|
+
glyph: import("@aethervtt/shard-core").FieldType<string, "object">;
|
|
12
|
+
rotation: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
13
|
+
}>, "object">;
|
|
14
|
+
/** A face layout: `data/**\/*.dice-layout.json`. */
|
|
15
|
+
export declare const FaceLayout: import("@aethervtt/shard-assets").DataType<{
|
|
16
|
+
readonly version: import("@aethervtt/shard-core").FieldType<number, "u8">;
|
|
17
|
+
readonly id: import("@aethervtt/shard-core").FieldType<string, "object">;
|
|
18
|
+
readonly default: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").InferFields<{
|
|
19
|
+
kind: import("@aethervtt/shard-core").FieldType<"blank" | "glyph" | "pips" | "text", "u8">;
|
|
20
|
+
text: import("@aethervtt/shard-core").FieldType<string, "object">;
|
|
21
|
+
font: import("@aethervtt/shard-core").FieldType<AssetRef<"Font"> | null, "object">;
|
|
22
|
+
size: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
23
|
+
weight: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
24
|
+
underline: import("@aethervtt/shard-core").FieldType<"always" | "auto" | "never", "u8">;
|
|
25
|
+
count: import("@aethervtt/shard-core").FieldType<number, "u8">;
|
|
26
|
+
glyph: import("@aethervtt/shard-core").FieldType<string, "object">;
|
|
27
|
+
rotation: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
28
|
+
}>, "object">;
|
|
29
|
+
readonly overrides: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").InferFields<{
|
|
30
|
+
value: import("@aethervtt/shard-core").FieldType<number, "u16">;
|
|
31
|
+
mark: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").InferFields<{
|
|
32
|
+
kind: import("@aethervtt/shard-core").FieldType<"blank" | "glyph" | "pips" | "text", "u8">;
|
|
33
|
+
text: import("@aethervtt/shard-core").FieldType<string, "object">;
|
|
34
|
+
font: import("@aethervtt/shard-core").FieldType<AssetRef<"Font"> | null, "object">;
|
|
35
|
+
size: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
36
|
+
weight: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
37
|
+
underline: import("@aethervtt/shard-core").FieldType<"always" | "auto" | "never", "u8">;
|
|
38
|
+
count: import("@aethervtt/shard-core").FieldType<number, "u8">;
|
|
39
|
+
glyph: import("@aethervtt/shard-core").FieldType<string, "object">;
|
|
40
|
+
rotation: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
41
|
+
}>, "object">;
|
|
42
|
+
}>[], "object">;
|
|
43
|
+
}, "dice/FaceLayout">;
|
|
44
|
+
export type FaceLayoutValue = Infer<typeof FaceLayout>;
|
|
45
|
+
export type FaceMark = FieldValue<typeof FaceMarkSchema>;
|
|
46
|
+
/** A mark ready to draw: text resolved to characters, pips to a count. */
|
|
47
|
+
export interface ResolvedMark {
|
|
48
|
+
kind: 'text' | 'pips' | 'glyph' | 'blank';
|
|
49
|
+
text: string;
|
|
50
|
+
font: AssetRef | null;
|
|
51
|
+
size: number;
|
|
52
|
+
weight: number;
|
|
53
|
+
underline: boolean;
|
|
54
|
+
count: number;
|
|
55
|
+
glyph: string;
|
|
56
|
+
/** Radians, clockwise. */
|
|
57
|
+
rotation: number;
|
|
58
|
+
}
|
|
59
|
+
/** Numbers on every face: each value's label, in the built-in numerals. */
|
|
60
|
+
export declare const NUMBERS_LAYOUT: FaceLayoutValue;
|
|
61
|
+
/** Pips on every face (up to 9). */
|
|
62
|
+
export declare const PIPS_LAYOUT: FaceLayoutValue;
|
|
63
|
+
/** The layout a die uses when its skin names none: pips on a d6, numbers everywhere else. */
|
|
64
|
+
export declare function defaultLayoutFor(def: DieDefinition): FaceLayoutValue;
|
|
65
|
+
/** Whether a label reads as another label of the die when the die is turned around. */
|
|
66
|
+
export declare function ambiguousLabel(def: DieDefinition, label: string): boolean;
|
|
67
|
+
/** The mark a value prints under a layout. */
|
|
68
|
+
export declare function resolveMark(layout: FaceLayoutValue, def: DieDefinition, value: number): ResolvedMark;
|
|
69
|
+
/**
|
|
70
|
+
* What a layout can't show on a die, by value: pips past 9, a glyph that isn't registered, text a
|
|
71
|
+
* font can't draw. Paths point into the layout.
|
|
72
|
+
*/
|
|
73
|
+
export declare function layoutProblems(layout: FaceLayoutValue, def: DieDefinition, canDraw?: (text: string, font: AssetRef | null) => boolean): ShardError[];
|
|
74
|
+
/** The built-in numerals draw digits only. */
|
|
75
|
+
export declare function builtinCanDraw(text: string, font: AssetRef | null): boolean;
|
package/dist/layout.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { defineDataType } from "@aethervtt/shard-assets";
|
|
2
|
+
import { ShardError, t } from "@aethervtt/shard-core";
|
|
3
|
+
import { labelOf } from "./definition.js";
|
|
4
|
+
import { findDiceGlyph } from "./glyphs.js";
|
|
5
|
+
const MARK_FIELDS = {
|
|
6
|
+
kind: t.enum(["text", "pips", "glyph", "blank"], {
|
|
7
|
+
description: "text prints characters (the value's label unless `text` says otherwise); pips draws dots; glyph draws a registered vector path; blank prints nothing."
|
|
8
|
+
}),
|
|
9
|
+
text: t.string({ description: "Text marks: what to print. Empty prints the value's label." }),
|
|
10
|
+
font: t.handle("Font", {
|
|
11
|
+
description: "Text marks: the font's outlines. Null uses the built-in numerals (digits only)."
|
|
12
|
+
}),
|
|
13
|
+
size: t.f32({ default: 1, min: 0.2, max: 2, description: "Scales the die's mark size." }),
|
|
14
|
+
weight: t.f32({
|
|
15
|
+
default: 0.035,
|
|
16
|
+
min: -0.05,
|
|
17
|
+
max: 0.12,
|
|
18
|
+
unit: "em",
|
|
19
|
+
description: "Thickens (or thins) text and glyph strokes, from the distance field."
|
|
20
|
+
}),
|
|
21
|
+
underline: t.enum(["auto", "always", "never"], {
|
|
22
|
+
description: "auto underlines a label that reads as another of the die\u2019s labels upside down (6 and 9, 16 and 91)."
|
|
23
|
+
}),
|
|
24
|
+
count: t.u8({ max: 9, description: "Pips: how many. 0 draws the value." }),
|
|
25
|
+
glyph: t.string({
|
|
26
|
+
description: "Glyph marks: the name of a registered glyph (defineDiceGlyph)."
|
|
27
|
+
}),
|
|
28
|
+
rotation: t.f32({ unit: "deg", description: "Turns the mark on its face, clockwise." })
|
|
29
|
+
};
|
|
30
|
+
const FaceMarkSchema = t.struct(MARK_FIELDS, { description: "One mark on a face." });
|
|
31
|
+
const FaceLayout = defineDataType(
|
|
32
|
+
"dice/FaceLayout",
|
|
33
|
+
{
|
|
34
|
+
version: t.u8({ default: 1, min: 1, max: 1, description: "Format version: 1." }),
|
|
35
|
+
id: t.string({ description: "A name for tools and errors." }),
|
|
36
|
+
default: FaceMarkSchema,
|
|
37
|
+
overrides: t.list(
|
|
38
|
+
t.struct({
|
|
39
|
+
value: t.u16({ min: 1, max: 100, description: "The value (not the face) it overrides." }),
|
|
40
|
+
mark: FaceMarkSchema
|
|
41
|
+
}),
|
|
42
|
+
{ description: "Marks for particular values, by value." }
|
|
43
|
+
)
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
extension: "dice-layout",
|
|
47
|
+
description: "What each value of a die prints: a default mark, and overrides by value."
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
const mark = (m) => ({
|
|
51
|
+
...FaceMarkSchema.defaultValue(),
|
|
52
|
+
...m
|
|
53
|
+
});
|
|
54
|
+
const NUMBERS_LAYOUT = {
|
|
55
|
+
version: 1,
|
|
56
|
+
id: "numbers",
|
|
57
|
+
default: mark({ kind: "text" }),
|
|
58
|
+
overrides: []
|
|
59
|
+
};
|
|
60
|
+
const PIPS_LAYOUT = {
|
|
61
|
+
version: 1,
|
|
62
|
+
id: "pips",
|
|
63
|
+
default: mark({ kind: "pips" }),
|
|
64
|
+
overrides: []
|
|
65
|
+
};
|
|
66
|
+
function defaultLayoutFor(def) {
|
|
67
|
+
return def.id === "d6" ? PIPS_LAYOUT : NUMBERS_LAYOUT;
|
|
68
|
+
}
|
|
69
|
+
const TURNED = { "0": "0", "1": "1", "6": "9", "8": "8", "9": "6" };
|
|
70
|
+
function upsideDown(label) {
|
|
71
|
+
let out = "";
|
|
72
|
+
for (let i = label.length - 1; i >= 0; i--) {
|
|
73
|
+
const c = TURNED[label[i]];
|
|
74
|
+
if (c === void 0) return void 0;
|
|
75
|
+
out += c;
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
function ambiguousLabel(def, label) {
|
|
80
|
+
const turned = upsideDown(label);
|
|
81
|
+
if (turned === void 0 || turned === label) return false;
|
|
82
|
+
for (let v = 1; v <= def.sides; v++) if (labelOf(def, v) === turned) return true;
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
function resolveMark(layout, def, value) {
|
|
86
|
+
const m = layout.overrides.find((o) => o.value === value)?.mark ?? layout.default;
|
|
87
|
+
const text = m.kind === "text" ? m.text || labelOf(def, value) : "";
|
|
88
|
+
return {
|
|
89
|
+
kind: m.kind,
|
|
90
|
+
text,
|
|
91
|
+
font: m.font,
|
|
92
|
+
size: m.size,
|
|
93
|
+
weight: m.weight,
|
|
94
|
+
underline: m.kind === "text" && (m.underline === "always" || m.underline === "auto" && ambiguousLabel(def, text)),
|
|
95
|
+
count: m.kind === "pips" ? m.count || value : 0,
|
|
96
|
+
glyph: m.glyph,
|
|
97
|
+
rotation: m.rotation * Math.PI / 180
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function layoutProblems(layout, def, canDraw = builtinCanDraw) {
|
|
101
|
+
const out = [];
|
|
102
|
+
for (let value = 1; value <= def.sides; value++) {
|
|
103
|
+
const index = layout.overrides.findIndex((o) => o.value === value);
|
|
104
|
+
const path = index >= 0 ? `/overrides/${index}/mark` : "/default";
|
|
105
|
+
const m = resolveMark(layout, def, value);
|
|
106
|
+
let problem;
|
|
107
|
+
if (m.kind === "pips" && (m.count < 1 || m.count > 9)) problem = `${m.count} pips (1 to 9 draw)`;
|
|
108
|
+
else if (m.kind === "glyph" && !findDiceGlyph(m.glyph))
|
|
109
|
+
problem = m.glyph ? `glyph "${m.glyph}", which isn't registered` : "a glyph with no name";
|
|
110
|
+
else if (m.kind === "text" && !canDraw(m.text, m.font))
|
|
111
|
+
problem = `"${m.text}", which the font can't draw`;
|
|
112
|
+
if (problem) {
|
|
113
|
+
out.push(
|
|
114
|
+
new ShardError(
|
|
115
|
+
"dice/layout-missing-value",
|
|
116
|
+
`Layout "${layout.id}" can't show ${value} on a ${def.id}: it asks for ${problem}`,
|
|
117
|
+
{ path, hint: `Give value ${value} a mark the die can draw, in overrides.` }
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
function builtinCanDraw(text, font) {
|
|
125
|
+
return font !== null || /^[0-9]+$/.test(text);
|
|
126
|
+
}
|
|
127
|
+
export {
|
|
128
|
+
FaceLayout,
|
|
129
|
+
FaceMarkSchema,
|
|
130
|
+
NUMBERS_LAYOUT,
|
|
131
|
+
PIPS_LAYOUT,
|
|
132
|
+
ambiguousLabel,
|
|
133
|
+
builtinCanDraw,
|
|
134
|
+
defaultLayoutFor,
|
|
135
|
+
layoutProblems,
|
|
136
|
+
resolveMark
|
|
137
|
+
};
|
package/dist/marks.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AssetRef } from '@aethervtt/shard-core';
|
|
2
|
+
import { type Font } from '@aethervtt/shard-text';
|
|
3
|
+
import { type CellLayout } from './cells.js';
|
|
4
|
+
import type { DieGeometry } from './definition.js';
|
|
5
|
+
import { type FaceLayoutValue, type ResolvedMark } from './layout.js';
|
|
6
|
+
export interface MarkAtlas {
|
|
7
|
+
/** What it was baked from: definition hash, layout, fonts. */
|
|
8
|
+
key: string;
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
layout: CellLayout;
|
|
12
|
+
/** Distance range in pixels. */
|
|
13
|
+
range: number;
|
|
14
|
+
pixels: Uint8Array;
|
|
15
|
+
/** Values drawn, per face (d4 faces carry three). */
|
|
16
|
+
values: number[][];
|
|
17
|
+
/** How long the bake took, ms. */
|
|
18
|
+
ms: number;
|
|
19
|
+
}
|
|
20
|
+
export interface BakeMarksOptions {
|
|
21
|
+
/** Loaded fonts for text marks that name one. */
|
|
22
|
+
font?: (ref: AssetRef) => Font | undefined;
|
|
23
|
+
}
|
|
24
|
+
export interface Placement {
|
|
25
|
+
mark: ResolvedMark;
|
|
26
|
+
/** Center in cell pixels (y up). */
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
/** Mark height in pixels. */
|
|
30
|
+
height: number;
|
|
31
|
+
/** Up direction angle, radians counter-clockwise from +y. */
|
|
32
|
+
angle: number;
|
|
33
|
+
/** The flat area the mark keeps inside, in cell pixels: [x0, y0, x1, y1, …]. */
|
|
34
|
+
region: number[];
|
|
35
|
+
/** The largest height the mark's ink can take there, keeping the margin clear. */
|
|
36
|
+
fit: number;
|
|
37
|
+
}
|
|
38
|
+
/** The share of a region's inscribed radius a mark's ink keeps clear of its edges. */
|
|
39
|
+
export declare const MARK_MARGIN = 0.12;
|
|
40
|
+
/**
|
|
41
|
+
* Every mark of a die under a layout, where the bake draws it: at the definition's height, shrunk
|
|
42
|
+
* (one scale for the whole die, so its numbers match) until every mark's ink fits its region.
|
|
43
|
+
*/
|
|
44
|
+
export declare function markPlacements(g: DieGeometry, layout: FaceLayoutValue, options?: BakeMarksOptions): Placement[][];
|
|
45
|
+
/** The cache key of a bake: the definition's hash, the layout's content, and its fonts' guids. */
|
|
46
|
+
export declare function markAtlasKey(g: DieGeometry, layout: FaceLayoutValue): string;
|
|
47
|
+
/**
|
|
48
|
+
* Bakes a die's marks under a layout into one MSDF atlas: glyph outlines from the font (or the
|
|
49
|
+
* built-in numerals), pips as analytic circles, glyphs from their registered paths. Cached by
|
|
50
|
+
* (definition, layout).
|
|
51
|
+
*/
|
|
52
|
+
export declare function bakeMarks(g: DieGeometry, layout: FaceLayoutValue, options?: BakeMarksOptions): MarkAtlas;
|
|
53
|
+
/** Drops every cached bake (tests, or a host changing fonts under the same refs). */
|
|
54
|
+
export declare function clearMarkCache(): void;
|