@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/hull.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import {
|
|
2
|
+
add,
|
|
3
|
+
cross,
|
|
4
|
+
dot,
|
|
5
|
+
EPSILON,
|
|
6
|
+
length,
|
|
7
|
+
normalize,
|
|
8
|
+
qConj,
|
|
9
|
+
qFromBasis,
|
|
10
|
+
qKey,
|
|
11
|
+
qMul,
|
|
12
|
+
qRotate,
|
|
13
|
+
round,
|
|
14
|
+
scale,
|
|
15
|
+
stableTangent,
|
|
16
|
+
sub
|
|
17
|
+
} from "./math.js";
|
|
18
|
+
function pointsOf(flat) {
|
|
19
|
+
const out = [];
|
|
20
|
+
for (let i = 0; i + 2 < flat.length; i += 3) out.push([flat[i], flat[i + 1], flat[i + 2]]);
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
const compareVector = (a, b) => a[1] - b[1] || a[2] - b[2] || a[0] - b[0];
|
|
24
|
+
function convexFaces(points) {
|
|
25
|
+
const faces = /* @__PURE__ */ new Map();
|
|
26
|
+
const n = points.length;
|
|
27
|
+
for (let a = 0; a < n - 2; a++) {
|
|
28
|
+
for (let b = a + 1; b < n - 1; b++) {
|
|
29
|
+
for (let c = b + 1; c < n; c++) {
|
|
30
|
+
let normal = cross(sub(points[b], points[a]), sub(points[c], points[a]));
|
|
31
|
+
if (dot(normal, normal) < 1e-10) continue;
|
|
32
|
+
normal = normalize(normal);
|
|
33
|
+
const d = dot(normal, points[a]);
|
|
34
|
+
let positive = false;
|
|
35
|
+
let negative = false;
|
|
36
|
+
for (const p of points) {
|
|
37
|
+
const side = dot(normal, p) - d;
|
|
38
|
+
if (side > EPSILON) positive = true;
|
|
39
|
+
else if (side < -EPSILON) negative = true;
|
|
40
|
+
if (positive && negative) break;
|
|
41
|
+
}
|
|
42
|
+
if (positive && negative) continue;
|
|
43
|
+
if (positive) normal = scale(normal, -1);
|
|
44
|
+
const plane = dot(normal, points[a]);
|
|
45
|
+
const members = [];
|
|
46
|
+
for (let i = 0; i < n; i++) {
|
|
47
|
+
if (Math.abs(dot(normal, points[i]) - plane) < EPSILON * 3) members.push(i);
|
|
48
|
+
}
|
|
49
|
+
const key = members.join(":");
|
|
50
|
+
if (faces.has(key)) continue;
|
|
51
|
+
let center = [0, 0, 0];
|
|
52
|
+
for (const i of members) center = add(center, points[i]);
|
|
53
|
+
center = scale(center, 1 / members.length);
|
|
54
|
+
faces.set(key, { vertices: orderAround(members, points, normal, center), normal, center });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return [...faces.values()].sort((l, r) => compareVector(l.normal, r.normal));
|
|
59
|
+
}
|
|
60
|
+
function orderAround(members, points, normal, center) {
|
|
61
|
+
const t = stableTangent(normal);
|
|
62
|
+
const b = cross(normal, t);
|
|
63
|
+
const angle = (i) => {
|
|
64
|
+
const d = sub(points[i], center);
|
|
65
|
+
return Math.atan2(dot(d, b), dot(d, t));
|
|
66
|
+
};
|
|
67
|
+
return [...members].sort((l, r) => angle(l) - angle(r));
|
|
68
|
+
}
|
|
69
|
+
function tangentPolytope(normals) {
|
|
70
|
+
const triangles = convexFaces(normals);
|
|
71
|
+
const points = [];
|
|
72
|
+
const cells = normals.map(() => []);
|
|
73
|
+
for (const tri of triangles) {
|
|
74
|
+
const [a, b, c] = tri.vertices;
|
|
75
|
+
const na = normals[a];
|
|
76
|
+
const nb = normals[b];
|
|
77
|
+
const nc = normals[c];
|
|
78
|
+
const det = dot(na, cross(nb, nc));
|
|
79
|
+
const p = scale(add(add(cross(nb, nc), cross(nc, na)), cross(na, nb)), 1 / det);
|
|
80
|
+
const index = points.push(p) - 1;
|
|
81
|
+
for (const i of tri.vertices) cells[i].push(index);
|
|
82
|
+
}
|
|
83
|
+
const faces = normals.map((normal, i) => {
|
|
84
|
+
let center = [0, 0, 0];
|
|
85
|
+
for (const v of cells[i]) center = add(center, points[v]);
|
|
86
|
+
center = scale(center, 1 / cells[i].length);
|
|
87
|
+
return { vertices: orderAround(cells[i], points, normal, center), normal, center };
|
|
88
|
+
});
|
|
89
|
+
return { points, faces };
|
|
90
|
+
}
|
|
91
|
+
function hasPoint(points, p) {
|
|
92
|
+
for (const q of points) {
|
|
93
|
+
const dx = q[0] - p[0];
|
|
94
|
+
const dy = q[1] - p[1];
|
|
95
|
+
const dz = q[2] - p[2];
|
|
96
|
+
if (dx * dx + dy * dy + dz * dz < EPSILON * EPSILON * 9) return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
function isSymmetry(points, q) {
|
|
101
|
+
for (const p of points) if (!hasPoint(points, qRotate(q, p))) return false;
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
function basisOf(a, b, c) {
|
|
105
|
+
const x = normalize(sub(b, a));
|
|
106
|
+
const ac = sub(c, a);
|
|
107
|
+
const yRaw = sub(ac, scale(x, dot(ac, x)));
|
|
108
|
+
if (length(yRaw) < 1e-6) return void 0;
|
|
109
|
+
const y = normalize(yRaw);
|
|
110
|
+
return [x, y, cross(x, y)];
|
|
111
|
+
}
|
|
112
|
+
function symmetryGroup(points) {
|
|
113
|
+
const n = points.length;
|
|
114
|
+
let anchor;
|
|
115
|
+
for (let b = 1; b < n && !anchor; b++) {
|
|
116
|
+
for (let c = b + 1; c < n && !anchor; c++) {
|
|
117
|
+
if (length(cross(sub(points[b], points[0]), sub(points[c], points[0]))) > 1e-4)
|
|
118
|
+
anchor = [0, b, c];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (!anchor) return [];
|
|
122
|
+
const [p0, p1, p2] = anchor.map((i) => points[i]);
|
|
123
|
+
const d01 = length(sub(p1, p0));
|
|
124
|
+
const d02 = length(sub(p2, p0));
|
|
125
|
+
const d12 = length(sub(p2, p1));
|
|
126
|
+
const source = basisOf(p0, p1, p2);
|
|
127
|
+
const fromSource = qConj(qFromBasis(...source));
|
|
128
|
+
const found = /* @__PURE__ */ new Map();
|
|
129
|
+
for (let a = 0; a < n; a++) {
|
|
130
|
+
for (let b = 0; b < n; b++) {
|
|
131
|
+
if (b === a || Math.abs(length(sub(points[b], points[a])) - d01) > EPSILON * 10) continue;
|
|
132
|
+
for (let c = 0; c < n; c++) {
|
|
133
|
+
if (c === a || c === b) continue;
|
|
134
|
+
if (Math.abs(length(sub(points[c], points[a])) - d02) > EPSILON * 10) continue;
|
|
135
|
+
if (Math.abs(length(sub(points[c], points[b])) - d12) > EPSILON * 10) continue;
|
|
136
|
+
const target = basisOf(points[a], points[b], points[c]);
|
|
137
|
+
if (!target) continue;
|
|
138
|
+
const q = qMul(qFromBasis(...target), fromSource);
|
|
139
|
+
const moved = qRotate(q, p0);
|
|
140
|
+
if (length(sub(moved, points[a])) > EPSILON * 10) continue;
|
|
141
|
+
if (!isSymmetry(points, q)) continue;
|
|
142
|
+
found.set(qKey(q), q.map(round));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return [...found.entries()].sort(([l], [r]) => l.localeCompare(r)).map(([, q]) => q);
|
|
147
|
+
}
|
|
148
|
+
export {
|
|
149
|
+
convexFaces,
|
|
150
|
+
isSymmetry,
|
|
151
|
+
pointsOf,
|
|
152
|
+
symmetryGroup,
|
|
153
|
+
tangentPolytope
|
|
154
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export { DICE_AUDIO_BUS } from './audio.js';
|
|
2
|
+
export { allDiceAttachments, DICE_BUDGETS, type DiceAttachmentContext, type DiceAttachmentDef, type DiceSceneContext, defineDiceAttachment, findDiceAttachment, MAX_ATTACHMENTS, setDiceBudgets, } from './attachments.js';
|
|
3
|
+
export { BUILTIN_DICE, D4, D6, D8, D10, D10_TENS, D12, D20, D100_BALL, DIE_KINDS, type DieKind, KIND_DEFINITIONS, kindSides, percentileValues, registerBuiltinDice, } from './builtins.js';
|
|
4
|
+
export { CELL_PAD, type CellLayout, cellLayout, type FaceCell, MARK_RANGE } from './cells.js';
|
|
5
|
+
export { DiceDie, DiceRollRequest } from './components.js';
|
|
6
|
+
export { allDice, type DieDefinition, type DieGeometry, defineDie, dieGeometry, dieHash, findDie, frameOf, labelOf, physicalScale, requireDie, type ValueFrame, validateDieDefinition, } from './definition.js';
|
|
7
|
+
export { DieDefinitionAsset, type DieDefinitionAssetValue, dieDefinitionOf, } from './definition-asset.js';
|
|
8
|
+
export { type DiceCondition, type DiceEffect, DiceEffectRecipe, type DiceEffectRecipeValue, diceEffectRecipe, type MatchedRecipe, matchRecipes, RECIPE_LIMITS, recipeProblems, } from './effects.js';
|
|
9
|
+
export { allDiceEntrances, type DiceEntranceContext, type DiceEntranceDef, defineDiceEntrance, findDiceEntrance, MAX_ENTRANCES, } from './entrances.js';
|
|
10
|
+
export { BUILTIN_FAMILIES, GLASS, METAL, RESIN, SOLID } from './families.js';
|
|
11
|
+
export { allDiceGlyphs, BUILTIN_GLYPHS, type DiceGlyph, type DiceGlyphDef, defineDiceGlyph, findDiceGlyph, parseSvgPath, registerBuiltinGlyphs, } from './glyphs.js';
|
|
12
|
+
export { landingCorrection, markAngle, naturalValue, restingHeight, restRotation, topAlignment, } from './landing.js';
|
|
13
|
+
export { ambiguousLabel, defaultLayoutFor, FaceLayout, type FaceLayoutValue, type FaceMark, layoutProblems, NUMBERS_LAYOUT, PIPS_LAYOUT, type ResolvedMark, resolveMark, } from './layout.js';
|
|
14
|
+
export { type BakeMarksOptions, bakeMarks, clearMarkCache, MARK_MARGIN, type MarkAtlas, markAtlasKey, markPlacements, type Placement as MarkPlacement, } from './marks.js';
|
|
15
|
+
export { allDiceFamilies, DICE_FIELDS, DICE_SHADERS, type DiceFamily, type DiceFamilyOptions, defineDiceFamily, findDiceFamily, isDiceMaterial, } from './material.js';
|
|
16
|
+
export { dieMesh, floorQuad } from './mesh.js';
|
|
17
|
+
export { diceMethods } from './methods.js';
|
|
18
|
+
export { NUMERAL_HEIGHT } from './numerals.js';
|
|
19
|
+
export { type DicePluginOptions, dicePlugin, TOP_DOWN } from './plugin.js';
|
|
20
|
+
export { type DiceThumbnail, type DiceThumbnailOptions, renderDiceThumbnail } from './preview.js';
|
|
21
|
+
export { type DiceQuality, type DiceQualityChoice, resolveDiceQuality } from './quality.js';
|
|
22
|
+
export { type DiceLookKey, type DiceResourceEntry, DiceResources, RELEASE_AFTER_MS, } from './resources.js';
|
|
23
|
+
export { type DiceQualityPreference, type DiceRoll, type DiceRollDie, expandRoll, type PhysicalDie, presentationScale, rollTrackRequest, viewportTray, } from './roll.js';
|
|
24
|
+
export { BALL_DAMPING, DICE_CLEANUP_STEP, DICE_GROUPS, DICE_SETTLE_RULE, type DiceSettleParams, type DiceTray, diceSettle, outsideTray, restingFlat, } from './settle.js';
|
|
25
|
+
export { BUILTIN_SKINS, DICE_SKINS, DiceSkin, type DiceSkinValue, type DiceSkinVariant, diceSkin, IMPACT_SOUNDS, type ImpactSound, MAX_SKIN_EFFECTS, type SkinContext, skinVariant, validateDiceSkin, } from './skin.js';
|
|
26
|
+
export { ACCENT_CUES, type AccentCue, accentSamples, DiceSoundBank, IMPACT_LAYERS, IMPACT_VARIATIONS, impactLayer, impactSamples, impactStrength, wavBytes, } from './sound.js';
|
|
27
|
+
export { studioEnvironment } from './studio.js';
|
|
28
|
+
export { ANIMATED_DEMAND, type DiceOutcome, type DicePhase, type DicePlayOptions, DiceTable, type DiceTableOptions, DiceTableState, ENTRANCE_DEMAND, ENTRANCE_WAIT_MS, PRESENTATION_DEMAND, PREVIEW_TRAY, } from './table.js';
|
|
29
|
+
export { DICE_CONTACTS, DICE_GRAVITY, DICE_MAX_STEPS, DICE_STEP, type DiceTrackDie, type DiceTrackRequest, diceSettleParams, diceTrackScene, LAUNCH_EDGES, type LaunchEdge, laneLayout, launchEdgeOf, MAX_DICE, PLACED_DROP_STEPS, placeDie, placedFrom, placementSpots, seedOf, type UnlandedReason, unlandedDice, } from './track.js';
|
|
30
|
+
export { DiceTray as DiceTrayMaterial, TRAY_SHADERS } from './tray.js';
|
|
31
|
+
export { type DiceVariantEntry, diceVariants } from './variants.js';
|
|
32
|
+
export { type DiceWindow, spawnDiceWindow } from './windows.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { DICE_AUDIO_BUS } from "./audio.js";
|
|
2
|
+
import {
|
|
3
|
+
allDiceAttachments,
|
|
4
|
+
DICE_BUDGETS,
|
|
5
|
+
defineDiceAttachment,
|
|
6
|
+
findDiceAttachment,
|
|
7
|
+
MAX_ATTACHMENTS,
|
|
8
|
+
setDiceBudgets
|
|
9
|
+
} from "./attachments.js";
|
|
10
|
+
import {
|
|
11
|
+
BUILTIN_DICE,
|
|
12
|
+
D4,
|
|
13
|
+
D6,
|
|
14
|
+
D8,
|
|
15
|
+
D10,
|
|
16
|
+
D10_TENS,
|
|
17
|
+
D12,
|
|
18
|
+
D20,
|
|
19
|
+
D100_BALL,
|
|
20
|
+
DIE_KINDS,
|
|
21
|
+
KIND_DEFINITIONS,
|
|
22
|
+
kindSides,
|
|
23
|
+
percentileValues,
|
|
24
|
+
registerBuiltinDice
|
|
25
|
+
} from "./builtins.js";
|
|
26
|
+
import { CELL_PAD, cellLayout, MARK_RANGE } from "./cells.js";
|
|
27
|
+
import { DiceDie, DiceRollRequest } from "./components.js";
|
|
28
|
+
import {
|
|
29
|
+
allDice,
|
|
30
|
+
defineDie,
|
|
31
|
+
dieGeometry,
|
|
32
|
+
dieHash,
|
|
33
|
+
findDie,
|
|
34
|
+
frameOf,
|
|
35
|
+
labelOf,
|
|
36
|
+
physicalScale,
|
|
37
|
+
requireDie,
|
|
38
|
+
validateDieDefinition
|
|
39
|
+
} from "./definition.js";
|
|
40
|
+
import {
|
|
41
|
+
DieDefinitionAsset,
|
|
42
|
+
dieDefinitionOf
|
|
43
|
+
} from "./definition-asset.js";
|
|
44
|
+
import {
|
|
45
|
+
DiceEffectRecipe,
|
|
46
|
+
diceEffectRecipe,
|
|
47
|
+
matchRecipes,
|
|
48
|
+
RECIPE_LIMITS,
|
|
49
|
+
recipeProblems
|
|
50
|
+
} from "./effects.js";
|
|
51
|
+
import {
|
|
52
|
+
allDiceEntrances,
|
|
53
|
+
defineDiceEntrance,
|
|
54
|
+
findDiceEntrance,
|
|
55
|
+
MAX_ENTRANCES
|
|
56
|
+
} from "./entrances.js";
|
|
57
|
+
import { BUILTIN_FAMILIES, GLASS, METAL, RESIN, SOLID } from "./families.js";
|
|
58
|
+
import {
|
|
59
|
+
allDiceGlyphs,
|
|
60
|
+
BUILTIN_GLYPHS,
|
|
61
|
+
defineDiceGlyph,
|
|
62
|
+
findDiceGlyph,
|
|
63
|
+
parseSvgPath,
|
|
64
|
+
registerBuiltinGlyphs
|
|
65
|
+
} from "./glyphs.js";
|
|
66
|
+
import {
|
|
67
|
+
landingCorrection,
|
|
68
|
+
markAngle,
|
|
69
|
+
naturalValue,
|
|
70
|
+
restingHeight,
|
|
71
|
+
restRotation,
|
|
72
|
+
topAlignment
|
|
73
|
+
} from "./landing.js";
|
|
74
|
+
import {
|
|
75
|
+
ambiguousLabel,
|
|
76
|
+
defaultLayoutFor,
|
|
77
|
+
FaceLayout,
|
|
78
|
+
layoutProblems,
|
|
79
|
+
NUMBERS_LAYOUT,
|
|
80
|
+
PIPS_LAYOUT,
|
|
81
|
+
resolveMark
|
|
82
|
+
} from "./layout.js";
|
|
83
|
+
import {
|
|
84
|
+
bakeMarks,
|
|
85
|
+
clearMarkCache,
|
|
86
|
+
MARK_MARGIN,
|
|
87
|
+
markAtlasKey,
|
|
88
|
+
markPlacements
|
|
89
|
+
} from "./marks.js";
|
|
90
|
+
import {
|
|
91
|
+
allDiceFamilies,
|
|
92
|
+
DICE_FIELDS,
|
|
93
|
+
DICE_SHADERS,
|
|
94
|
+
defineDiceFamily,
|
|
95
|
+
findDiceFamily,
|
|
96
|
+
isDiceMaterial
|
|
97
|
+
} from "./material.js";
|
|
98
|
+
import { dieMesh, floorQuad } from "./mesh.js";
|
|
99
|
+
import { diceMethods } from "./methods.js";
|
|
100
|
+
import { NUMERAL_HEIGHT } from "./numerals.js";
|
|
101
|
+
import { dicePlugin, TOP_DOWN } from "./plugin.js";
|
|
102
|
+
import { renderDiceThumbnail } from "./preview.js";
|
|
103
|
+
import { resolveDiceQuality } from "./quality.js";
|
|
104
|
+
import {
|
|
105
|
+
DiceResources,
|
|
106
|
+
RELEASE_AFTER_MS
|
|
107
|
+
} from "./resources.js";
|
|
108
|
+
import {
|
|
109
|
+
expandRoll,
|
|
110
|
+
presentationScale,
|
|
111
|
+
rollTrackRequest,
|
|
112
|
+
viewportTray
|
|
113
|
+
} from "./roll.js";
|
|
114
|
+
import {
|
|
115
|
+
BALL_DAMPING,
|
|
116
|
+
DICE_CLEANUP_STEP,
|
|
117
|
+
DICE_GROUPS,
|
|
118
|
+
DICE_SETTLE_RULE,
|
|
119
|
+
diceSettle,
|
|
120
|
+
outsideTray,
|
|
121
|
+
restingFlat
|
|
122
|
+
} from "./settle.js";
|
|
123
|
+
import {
|
|
124
|
+
BUILTIN_SKINS,
|
|
125
|
+
DICE_SKINS,
|
|
126
|
+
DiceSkin,
|
|
127
|
+
diceSkin,
|
|
128
|
+
IMPACT_SOUNDS,
|
|
129
|
+
MAX_SKIN_EFFECTS,
|
|
130
|
+
skinVariant,
|
|
131
|
+
validateDiceSkin
|
|
132
|
+
} from "./skin.js";
|
|
133
|
+
import {
|
|
134
|
+
ACCENT_CUES,
|
|
135
|
+
accentSamples,
|
|
136
|
+
DiceSoundBank,
|
|
137
|
+
IMPACT_LAYERS,
|
|
138
|
+
IMPACT_VARIATIONS,
|
|
139
|
+
impactLayer,
|
|
140
|
+
impactSamples,
|
|
141
|
+
impactStrength,
|
|
142
|
+
wavBytes
|
|
143
|
+
} from "./sound.js";
|
|
144
|
+
import { studioEnvironment } from "./studio.js";
|
|
145
|
+
import {
|
|
146
|
+
ANIMATED_DEMAND,
|
|
147
|
+
DiceTable,
|
|
148
|
+
DiceTableState,
|
|
149
|
+
ENTRANCE_DEMAND,
|
|
150
|
+
ENTRANCE_WAIT_MS,
|
|
151
|
+
PRESENTATION_DEMAND,
|
|
152
|
+
PREVIEW_TRAY
|
|
153
|
+
} from "./table.js";
|
|
154
|
+
import {
|
|
155
|
+
DICE_CONTACTS,
|
|
156
|
+
DICE_GRAVITY,
|
|
157
|
+
DICE_MAX_STEPS,
|
|
158
|
+
DICE_STEP,
|
|
159
|
+
diceSettleParams,
|
|
160
|
+
diceTrackScene,
|
|
161
|
+
LAUNCH_EDGES,
|
|
162
|
+
laneLayout,
|
|
163
|
+
launchEdgeOf,
|
|
164
|
+
MAX_DICE,
|
|
165
|
+
PLACED_DROP_STEPS,
|
|
166
|
+
placeDie,
|
|
167
|
+
placedFrom,
|
|
168
|
+
placementSpots,
|
|
169
|
+
seedOf,
|
|
170
|
+
unlandedDice
|
|
171
|
+
} from "./track.js";
|
|
172
|
+
import { DiceTray, TRAY_SHADERS } from "./tray.js";
|
|
173
|
+
import { diceVariants } from "./variants.js";
|
|
174
|
+
import { spawnDiceWindow } from "./windows.js";
|
|
175
|
+
export {
|
|
176
|
+
ACCENT_CUES,
|
|
177
|
+
ANIMATED_DEMAND,
|
|
178
|
+
BALL_DAMPING,
|
|
179
|
+
BUILTIN_DICE,
|
|
180
|
+
BUILTIN_FAMILIES,
|
|
181
|
+
BUILTIN_GLYPHS,
|
|
182
|
+
BUILTIN_SKINS,
|
|
183
|
+
CELL_PAD,
|
|
184
|
+
D10,
|
|
185
|
+
D100_BALL,
|
|
186
|
+
D10_TENS,
|
|
187
|
+
D12,
|
|
188
|
+
D20,
|
|
189
|
+
D4,
|
|
190
|
+
D6,
|
|
191
|
+
D8,
|
|
192
|
+
DICE_AUDIO_BUS,
|
|
193
|
+
DICE_BUDGETS,
|
|
194
|
+
DICE_CLEANUP_STEP,
|
|
195
|
+
DICE_CONTACTS,
|
|
196
|
+
DICE_FIELDS,
|
|
197
|
+
DICE_GRAVITY,
|
|
198
|
+
DICE_GROUPS,
|
|
199
|
+
DICE_MAX_STEPS,
|
|
200
|
+
DICE_SETTLE_RULE,
|
|
201
|
+
DICE_SHADERS,
|
|
202
|
+
DICE_SKINS,
|
|
203
|
+
DICE_STEP,
|
|
204
|
+
DIE_KINDS,
|
|
205
|
+
DiceDie,
|
|
206
|
+
DiceEffectRecipe,
|
|
207
|
+
DiceResources,
|
|
208
|
+
DiceRollRequest,
|
|
209
|
+
DiceSkin,
|
|
210
|
+
DiceSoundBank,
|
|
211
|
+
DiceTable,
|
|
212
|
+
DiceTableState,
|
|
213
|
+
DiceTray as DiceTrayMaterial,
|
|
214
|
+
DieDefinitionAsset,
|
|
215
|
+
ENTRANCE_DEMAND,
|
|
216
|
+
ENTRANCE_WAIT_MS,
|
|
217
|
+
FaceLayout,
|
|
218
|
+
GLASS,
|
|
219
|
+
IMPACT_LAYERS,
|
|
220
|
+
IMPACT_SOUNDS,
|
|
221
|
+
IMPACT_VARIATIONS,
|
|
222
|
+
KIND_DEFINITIONS,
|
|
223
|
+
LAUNCH_EDGES,
|
|
224
|
+
MARK_MARGIN,
|
|
225
|
+
MARK_RANGE,
|
|
226
|
+
MAX_ATTACHMENTS,
|
|
227
|
+
MAX_DICE,
|
|
228
|
+
MAX_ENTRANCES,
|
|
229
|
+
MAX_SKIN_EFFECTS,
|
|
230
|
+
METAL,
|
|
231
|
+
NUMBERS_LAYOUT,
|
|
232
|
+
NUMERAL_HEIGHT,
|
|
233
|
+
PIPS_LAYOUT,
|
|
234
|
+
PLACED_DROP_STEPS,
|
|
235
|
+
PRESENTATION_DEMAND,
|
|
236
|
+
PREVIEW_TRAY,
|
|
237
|
+
RECIPE_LIMITS,
|
|
238
|
+
RELEASE_AFTER_MS,
|
|
239
|
+
RESIN,
|
|
240
|
+
SOLID,
|
|
241
|
+
TOP_DOWN,
|
|
242
|
+
TRAY_SHADERS,
|
|
243
|
+
accentSamples,
|
|
244
|
+
allDice,
|
|
245
|
+
allDiceAttachments,
|
|
246
|
+
allDiceEntrances,
|
|
247
|
+
allDiceFamilies,
|
|
248
|
+
allDiceGlyphs,
|
|
249
|
+
ambiguousLabel,
|
|
250
|
+
bakeMarks,
|
|
251
|
+
cellLayout,
|
|
252
|
+
clearMarkCache,
|
|
253
|
+
defaultLayoutFor,
|
|
254
|
+
defineDiceAttachment,
|
|
255
|
+
defineDiceEntrance,
|
|
256
|
+
defineDiceFamily,
|
|
257
|
+
defineDiceGlyph,
|
|
258
|
+
defineDie,
|
|
259
|
+
diceEffectRecipe,
|
|
260
|
+
diceMethods,
|
|
261
|
+
dicePlugin,
|
|
262
|
+
diceSettle,
|
|
263
|
+
diceSettleParams,
|
|
264
|
+
diceSkin,
|
|
265
|
+
diceTrackScene,
|
|
266
|
+
diceVariants,
|
|
267
|
+
dieDefinitionOf,
|
|
268
|
+
dieGeometry,
|
|
269
|
+
dieHash,
|
|
270
|
+
dieMesh,
|
|
271
|
+
expandRoll,
|
|
272
|
+
findDiceAttachment,
|
|
273
|
+
findDiceEntrance,
|
|
274
|
+
findDiceFamily,
|
|
275
|
+
findDiceGlyph,
|
|
276
|
+
findDie,
|
|
277
|
+
floorQuad,
|
|
278
|
+
frameOf,
|
|
279
|
+
impactLayer,
|
|
280
|
+
impactSamples,
|
|
281
|
+
impactStrength,
|
|
282
|
+
isDiceMaterial,
|
|
283
|
+
kindSides,
|
|
284
|
+
labelOf,
|
|
285
|
+
landingCorrection,
|
|
286
|
+
laneLayout,
|
|
287
|
+
launchEdgeOf,
|
|
288
|
+
layoutProblems,
|
|
289
|
+
markAngle,
|
|
290
|
+
markAtlasKey,
|
|
291
|
+
markPlacements,
|
|
292
|
+
matchRecipes,
|
|
293
|
+
naturalValue,
|
|
294
|
+
outsideTray,
|
|
295
|
+
parseSvgPath,
|
|
296
|
+
percentileValues,
|
|
297
|
+
physicalScale,
|
|
298
|
+
placeDie,
|
|
299
|
+
placedFrom,
|
|
300
|
+
placementSpots,
|
|
301
|
+
presentationScale,
|
|
302
|
+
recipeProblems,
|
|
303
|
+
registerBuiltinDice,
|
|
304
|
+
registerBuiltinGlyphs,
|
|
305
|
+
renderDiceThumbnail,
|
|
306
|
+
requireDie,
|
|
307
|
+
resolveDiceQuality,
|
|
308
|
+
resolveMark,
|
|
309
|
+
restRotation,
|
|
310
|
+
restingFlat,
|
|
311
|
+
restingHeight,
|
|
312
|
+
rollTrackRequest,
|
|
313
|
+
seedOf,
|
|
314
|
+
setDiceBudgets,
|
|
315
|
+
skinVariant,
|
|
316
|
+
spawnDiceWindow,
|
|
317
|
+
studioEnvironment,
|
|
318
|
+
topAlignment,
|
|
319
|
+
unlandedDice,
|
|
320
|
+
validateDiceSkin,
|
|
321
|
+
validateDieDefinition,
|
|
322
|
+
viewportTray,
|
|
323
|
+
wavBytes
|
|
324
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type DieDefinition, type DieGeometry } from './definition.js';
|
|
2
|
+
import { type Q4, type V3 } from './math.js';
|
|
3
|
+
/** Screen-up as a direction on the floor (the camera's up, flattened). */
|
|
4
|
+
export declare function floorUp(screenUp: ArrayLike<number>): V3;
|
|
5
|
+
/** The value on top for a body rotation: the one whose direction points most nearly up. */
|
|
6
|
+
export declare function naturalValue(die: DieDefinition | DieGeometry, rotation: ArrayLike<number>): number;
|
|
7
|
+
/** How nearly the top value's direction points up: 1 when it's exactly vertical. */
|
|
8
|
+
export declare function topAlignment(die: DieDefinition | DieGeometry, rotation: ArrayLike<number>): number;
|
|
9
|
+
/**
|
|
10
|
+
* The angle (radians) between a value's mark-up on screen and screen-up, both flattened onto the
|
|
11
|
+
* floor, for a die shown at `rotation`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function markAngle(die: DieDefinition | DieGeometry, rotation: ArrayLike<number>, value: number, screenUp?: ArrayLike<number>): number;
|
|
14
|
+
/**
|
|
15
|
+
* The correction for a die that came to rest at `finalRotation`: a symmetry C of its collider,
|
|
16
|
+
* post-multiplied onto every sampled rotation (shown = rotation · C), that puts `target` where the
|
|
17
|
+
* natural value is. Among the symmetries that do, it's the one whose mark reads closest to
|
|
18
|
+
* screen-up. A ball's group is every rotation, so its target ends exactly up and upright. Throws
|
|
19
|
+
* `dice/invalid-value` for a value the die can't show.
|
|
20
|
+
*/
|
|
21
|
+
export declare function landingCorrection(die: DieDefinition | DieGeometry, finalRotation: ArrayLike<number>, target: number, screenUp?: ArrayLike<number>): Q4;
|
|
22
|
+
/**
|
|
23
|
+
* A rotation that rests `target` on top with its mark exactly toward screen-up: reduced motion,
|
|
24
|
+
* placed dice and thumbnails. The face opposite rests on the floor (a d4 rests on the face
|
|
25
|
+
* opposite its vertex).
|
|
26
|
+
*/
|
|
27
|
+
export declare function restRotation(die: DieDefinition | DieGeometry, target: number, screenUp?: ArrayLike<number>): Q4;
|
|
28
|
+
/** The height of the die's center above the floor at `rotation`: its lowest point touches it. */
|
|
29
|
+
export declare function restingHeight(die: DieDefinition | DieGeometry, rotation: ArrayLike<number>, scale: number): number;
|
package/dist/landing.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { dieGeometry, frameOf } from "./definition.js";
|
|
2
|
+
import {
|
|
3
|
+
angleBetween,
|
|
4
|
+
dot,
|
|
5
|
+
EPSILON,
|
|
6
|
+
length,
|
|
7
|
+
normalize,
|
|
8
|
+
qConj,
|
|
9
|
+
qFromFrames,
|
|
10
|
+
qMul,
|
|
11
|
+
qNormalize,
|
|
12
|
+
qRotate,
|
|
13
|
+
sub
|
|
14
|
+
} from "./math.js";
|
|
15
|
+
const UP = [0, 1, 0];
|
|
16
|
+
const geometryOf = (die) => "frames" in die ? die : dieGeometry(die);
|
|
17
|
+
const quat = (q) => qNormalize([q[0], q[1], q[2], q[3]]);
|
|
18
|
+
function floorUp(screenUp) {
|
|
19
|
+
const flat = [screenUp[0], 0, screenUp[2]];
|
|
20
|
+
const l = length(flat);
|
|
21
|
+
return l > 1e-6 ? [flat[0] / l, 0, flat[2] / l] : [0, 0, -1];
|
|
22
|
+
}
|
|
23
|
+
function naturalValue(die, rotation) {
|
|
24
|
+
const g = geometryOf(die);
|
|
25
|
+
const q = quat(rotation);
|
|
26
|
+
let best = g.frames[0].value;
|
|
27
|
+
let height = Number.NEGATIVE_INFINITY;
|
|
28
|
+
for (const frame of g.frames) {
|
|
29
|
+
const y = qRotate(q, frame.normal)[1];
|
|
30
|
+
if (y > height) {
|
|
31
|
+
height = y;
|
|
32
|
+
best = frame.value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return best;
|
|
36
|
+
}
|
|
37
|
+
function topAlignment(die, rotation) {
|
|
38
|
+
const g = geometryOf(die);
|
|
39
|
+
if (g.definition.collider === "ball") return 1;
|
|
40
|
+
const q = quat(rotation);
|
|
41
|
+
let height = Number.NEGATIVE_INFINITY;
|
|
42
|
+
for (const frame of g.frames) height = Math.max(height, qRotate(q, frame.normal)[1]);
|
|
43
|
+
return height;
|
|
44
|
+
}
|
|
45
|
+
function markAngle(die, rotation, value, screenUp = [0, 0, -1]) {
|
|
46
|
+
const g = geometryOf(die);
|
|
47
|
+
const b = qRotate(quat(rotation), frameOf(g, value).bitangent);
|
|
48
|
+
return angleBetween(normalize([b[0], 0, b[2]]), floorUp(screenUp));
|
|
49
|
+
}
|
|
50
|
+
function landingCorrection(die, finalRotation, target, screenUp = [0, 0, -1]) {
|
|
51
|
+
const g = geometryOf(die);
|
|
52
|
+
const frame = frameOf(g, target);
|
|
53
|
+
const r = quat(finalRotation);
|
|
54
|
+
const up = floorUp(screenUp);
|
|
55
|
+
if (g.definition.collider === "ball") {
|
|
56
|
+
return qNormalize(qMul(qConj(r), qFromFrames(frame.normal, frame.bitangent, UP, up)));
|
|
57
|
+
}
|
|
58
|
+
const natural = frameOf(g, naturalValue(g, r));
|
|
59
|
+
let best;
|
|
60
|
+
let score = Number.NEGATIVE_INFINITY;
|
|
61
|
+
for (const c of g.symmetries) {
|
|
62
|
+
if (length(sub(qRotate(c, frame.normal), natural.normal)) > EPSILON * 10) continue;
|
|
63
|
+
const b = qRotate(r, qRotate(c, frame.bitangent));
|
|
64
|
+
const s = dot(normalize([b[0], 0, b[2]]), up);
|
|
65
|
+
if (s > score + 1e-9) {
|
|
66
|
+
score = s;
|
|
67
|
+
best = c;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return best ?? [0, 0, 0, 1];
|
|
71
|
+
}
|
|
72
|
+
function restRotation(die, target, screenUp = [0, 0, -1]) {
|
|
73
|
+
const g = geometryOf(die);
|
|
74
|
+
const frame = frameOf(g, target);
|
|
75
|
+
return qFromFrames(frame.normal, frame.bitangent, UP, floorUp(screenUp));
|
|
76
|
+
}
|
|
77
|
+
function restingHeight(die, rotation, scale) {
|
|
78
|
+
const g = geometryOf(die);
|
|
79
|
+
if (g.definition.collider === "ball") return scale;
|
|
80
|
+
const q = quat(rotation);
|
|
81
|
+
let low = 0;
|
|
82
|
+
for (const p of g.points) low = Math.min(low, qRotate(q, p)[1]);
|
|
83
|
+
return -low * scale;
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
floorUp,
|
|
87
|
+
landingCorrection,
|
|
88
|
+
markAngle,
|
|
89
|
+
naturalValue,
|
|
90
|
+
restRotation,
|
|
91
|
+
restingHeight,
|
|
92
|
+
topAlignment
|
|
93
|
+
};
|