rig-c 0.0.0-stage → 2.20.4
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/.claude-plugin/marketplace.json +19 -0
- package/.claude-plugin/plugin.json +13 -0
- package/LICENSE +30 -0
- package/NOTICE.md +145 -0
- package/README.md +817 -3
- package/bin/rigc.cjs +83 -0
- package/cli.ts +61 -0
- package/cli_core.ts +46 -0
- package/docs/AUTHORING.md +9923 -0
- package/docs/FACE.md +1948 -0
- package/docs/INGEST.md +1488 -0
- package/docs/MOTION.md +1241 -0
- package/docs/PROMPTING.md +109 -0
- package/docs/RIGGING.md +1441 -0
- package/docs/SPEC_COVERAGE.md +357 -0
- package/package.json +108 -4
- package/skills/rigc/SKILL.md +133 -0
- package/skills/rigc-face/SKILL.md +60 -0
- package/skills/rigc-ingest/SKILL.md +78 -0
- package/skills/rigc-motion/SKILL.md +51 -0
- package/skills/rigc-rigging/SKILL.md +49 -0
- package/src/areaband.ts +159 -0
- package/src/assertions/bodies/a01.ts +23 -0
- package/src/assertions/bodies/a02.ts +21 -0
- package/src/assertions/bodies/a03.ts +27 -0
- package/src/assertions/bodies/a04.ts +40 -0
- package/src/assertions/bodies/a05.ts +56 -0
- package/src/assertions/bodies/a06.ts +245 -0
- package/src/assertions/bodies/a07.ts +68 -0
- package/src/assertions/bodies/a08.ts +76 -0
- package/src/assertions/bodies/a09.ts +82 -0
- package/src/assertions/bodies/a10.ts +116 -0
- package/src/assertions/bodies/a11.ts +15 -0
- package/src/assertions/bodies/a12.ts +30 -0
- package/src/assertions/bodies/a13.ts +51 -0
- package/src/assertions/bodies/a14.ts +35 -0
- package/src/assertions/bodies/a15.ts +97 -0
- package/src/assertions/bodies/a16.ts +24 -0
- package/src/assertions/bodies/a17.ts +26 -0
- package/src/assertions/bodies/a18.ts +62 -0
- package/src/assertions/bodies/a19.ts +404 -0
- package/src/assertions/bodies/a20.ts +122 -0
- package/src/assertions/bodies/a21.ts +190 -0
- package/src/assertions/bodies/a22.ts +39 -0
- package/src/assertions/bodies/a23.ts +305 -0
- package/src/assertions/bodies/a24.ts +68 -0
- package/src/assertions/bodies/a25.ts +39 -0
- package/src/assertions/bodies/a26.ts +61 -0
- package/src/assertions/bodies/a27.ts +33 -0
- package/src/assertions/bodies/a28.ts +70 -0
- package/src/assertions/bodies/a29.ts +34 -0
- package/src/assertions/bodies/a30.ts +50 -0
- package/src/assertions/bodies/a31.ts +61 -0
- package/src/assertions/bodies/a32.ts +44 -0
- package/src/assertions/bodies/a33.ts +110 -0
- package/src/assertions/bodies/a34.ts +133 -0
- package/src/assertions/bodies/a35.ts +160 -0
- package/src/assertions/bodies/a36.ts +81 -0
- package/src/assertions/bodies/a37.ts +77 -0
- package/src/assertions/bodies/a38.ts +73 -0
- package/src/assertions/bodies/a39.ts +303 -0
- package/src/assertions/bodies/a40.ts +128 -0
- package/src/assertions/bodies/a42.ts +97 -0
- package/src/assertions/bodies/a43.ts +181 -0
- package/src/assertions/bodies/a44.ts +23 -0
- package/src/assertions/bodies/a45.ts +172 -0
- package/src/assertions/bodies/a46.ts +224 -0
- package/src/assertions/bodies/a47.ts +126 -0
- package/src/assertions/bodies/a48.ts +83 -0
- package/src/assertions/bodies/a49.ts +81 -0
- package/src/assertions/bodies/a50.ts +97 -0
- package/src/assertions/constraint_words.ts +169 -0
- package/src/assertions/emitted/index.ts +148 -0
- package/src/assertions/facts/animated_bones.ts +30 -0
- package/src/assertions/facts/animation_durations.ts +37 -0
- package/src/assertions/facts/atlas_pages.ts +19 -0
- package/src/assertions/facts/atlas_regions.ts +52 -0
- package/src/assertions/facts/bone_timelines.ts +37 -0
- package/src/assertions/facts/constraint_targets.ts +56 -0
- package/src/assertions/facts/constraints.ts +155 -0
- package/src/assertions/facts/deform_survey.ts +27 -0
- package/src/assertions/facts/event_keys.ts +55 -0
- package/src/assertions/facts/linked_meshes.ts +38 -0
- package/src/assertions/facts/mesh_attachments.ts +100 -0
- package/src/assertions/facts/region_joins.ts +34 -0
- package/src/assertions/facts/sequences.ts +85 -0
- package/src/assertions/facts/skeleton_roster.ts +45 -0
- package/src/assertions/facts/skin_entries.ts +37 -0
- package/src/assertions/facts/skin_members.ts +53 -0
- package/src/assertions/facts/slider_composition.ts +78 -0
- package/src/assertions/facts/slot_colour.ts +43 -0
- package/src/assertions/facts/stage.ts +27 -0
- package/src/assertions/facts/stage_box.ts +65 -0
- package/src/assertions/facts/stepped_poses.ts +74 -0
- package/src/assertions/facts/two_colour.ts +52 -0
- package/src/assertions/facts/vertex_polygons.ts +53 -0
- package/src/assertions/footprints.ts +367 -0
- package/src/assertions/harness.ts +109 -0
- package/src/assertions/inward_advance.ts +58 -0
- package/src/assertions/kinds.ts +105 -0
- package/src/assertions/mesh_kinds.ts +56 -0
- package/src/assertions/model/animated_bones.ts +38 -0
- package/src/assertions/model/animation_durations.ts +57 -0
- package/src/assertions/model/atlas_pages.ts +15 -0
- package/src/assertions/model/atlas_regions.ts +76 -0
- package/src/assertions/model/bone_timelines.ts +58 -0
- package/src/assertions/model/constraint_targets.ts +82 -0
- package/src/assertions/model/constraints.ts +233 -0
- package/src/assertions/model/declared.ts +125 -0
- package/src/assertions/model/deform_survey.ts +24 -0
- package/src/assertions/model/event_keys.ts +45 -0
- package/src/assertions/model/given.ts +45 -0
- package/src/assertions/model/index.ts +398 -0
- package/src/assertions/model/linked_meshes.ts +24 -0
- package/src/assertions/model/mesh_attachments.ts +119 -0
- package/src/assertions/model/parse.ts +146 -0
- package/src/assertions/model/region_joins.ts +67 -0
- package/src/assertions/model/runtime_timelines.ts +78 -0
- package/src/assertions/model/sequences.ts +157 -0
- package/src/assertions/model/skeleton_roster.ts +23 -0
- package/src/assertions/model/skin_entries.ts +69 -0
- package/src/assertions/model/skin_members.ts +64 -0
- package/src/assertions/model/slider_composition.ts +193 -0
- package/src/assertions/model/slot_colour.ts +81 -0
- package/src/assertions/model/stage.ts +28 -0
- package/src/assertions/model/stage_box.ts +51 -0
- package/src/assertions/model/stepped_poses.ts +105 -0
- package/src/assertions/model/two_colour.ts +61 -0
- package/src/assertions/model/vertex_polygons.ts +72 -0
- package/src/assertions/reasons.ts +129 -0
- package/src/assertions/region_lookups.ts +61 -0
- package/src/assertions/report.ts +189 -0
- package/src/assertions/values.ts +39 -0
- package/src/atlas.ts +2870 -0
- package/src/ballot.ts +866 -0
- package/src/bonedist.ts +643 -0
- package/src/chainfit.ts +2752 -0
- package/src/chains.ts +170 -0
- package/src/check.ts +4303 -0
- package/src/checkpics.ts +295 -0
- package/src/cli/core_commands.ts +1627 -0
- package/src/cli/repack.ts +414 -0
- package/src/cli/shared.ts +2776 -0
- package/src/cli/spine_commands.ts +820 -0
- package/src/compile.ts +9414 -0
- package/src/core/additive.ts +458 -0
- package/src/core/animation.ts +1050 -0
- package/src/core/clipping.ts +696 -0
- package/src/core/constraints.ts +1876 -0
- package/src/core/constraints_path.ts +964 -0
- package/src/core/constraints_physics.ts +881 -0
- package/src/core/constraints_slider.ts +635 -0
- package/src/core/deform.ts +613 -0
- package/src/core/draw_order.ts +125 -0
- package/src/core/events.ts +135 -0
- package/src/core/hooks.ts +249 -0
- package/src/core/index.ts +1400 -0
- package/src/core/raw.ts +739 -0
- package/src/core/skins.ts +129 -0
- package/src/core/uvs.ts +469 -0
- package/src/core/vertices.ts +490 -0
- package/src/core/walk.ts +197 -0
- package/src/core/world.ts +289 -0
- package/src/correspondence.ts +15 -0
- package/src/deformbuild.ts +60 -0
- package/src/deformgen.ts +630 -0
- package/src/deformmeasure.ts +732 -0
- package/src/deformreport.ts +373 -0
- package/src/deformstructure.ts +386 -0
- package/src/deformsurvey.ts +2162 -0
- package/src/depth.ts +784 -0
- package/src/diff.ts +2252 -0
- package/src/emit.ts +134 -0
- package/src/emit_spine.ts +854 -0
- package/src/errors.ts +53 -0
- package/src/framing.ts +819 -0
- package/src/generation.ts +139 -0
- package/src/ingest.ts +2293 -0
- package/src/json-position.ts +253 -0
- package/src/keyorder.ts +587 -0
- package/src/keys.ts +486 -0
- package/src/ladder.ts +121 -0
- package/src/mesh.ts +2382 -0
- package/src/meshcompare.ts +1188 -0
- package/src/meshquality.ts +2042 -0
- package/src/meshrasters.ts +944 -0
- package/src/meshreduce.ts +1425 -0
- package/src/model.ts +1245 -0
- package/src/motion.ts +809 -0
- package/src/nonfinite.ts +54 -0
- package/src/package_meta.ts +48 -0
- package/src/png.ts +297 -0
- package/src/pose.ts +2324 -0
- package/src/preview.ts +434 -0
- package/src/region_joins.ts +54 -0
- package/src/render.ts +1013 -0
- package/src/render_core.ts +871 -0
- package/src/render_shared.ts +2958 -0
- package/src/repack.ts +495 -0
- package/src/rig.ts +2941 -0
- package/src/slots.ts +892 -0
- package/src/spine_side.ts +138 -0
- package/src/timelines.ts +837 -0
- package/src/trackgen.ts +364 -0
- package/src/transform.ts +310 -0
- package/src/types.ts +1797 -0
- package/src/validate.ts +3875 -0
- package/tools/contact.ts +126 -0
- package/tools/editor_roundtrip.ts +1641 -0
- package/tools/font5x7.ts +101 -0
- package/tools/measure_contact_depth.ts +105 -0
- package/tools/plate.ts +508 -0
- package/tools/png_probe.mjs +72 -0
package/tools/font5x7.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A 5x7 bitmap font, uppercase + digits + a little punctuation.
|
|
3
|
+
*
|
|
4
|
+
* It exists so a generated plate can burn its own name into its own pixels with
|
|
5
|
+
* no font file, no canvas and no dependency. That matters more than it sounds:
|
|
6
|
+
* the whole point of a synthetic stand-in plate is that nobody can mistake it
|
|
7
|
+
* for real art, and the strongest form of that is the word PLACEHOLDER sitting
|
|
8
|
+
* in the image itself.
|
|
9
|
+
*
|
|
10
|
+
* Each glyph is 7 rows of 5 bits, MSB = leftmost column.
|
|
11
|
+
*/
|
|
12
|
+
const GLYPHS: Record<string, number[]> = {
|
|
13
|
+
A: [0x0e, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11],
|
|
14
|
+
B: [0x1e, 0x11, 0x11, 0x1e, 0x11, 0x11, 0x1e],
|
|
15
|
+
C: [0x0e, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0e],
|
|
16
|
+
D: [0x1e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1e],
|
|
17
|
+
E: [0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x1f],
|
|
18
|
+
F: [0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x10],
|
|
19
|
+
G: [0x0e, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0e],
|
|
20
|
+
H: [0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11],
|
|
21
|
+
I: [0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0e],
|
|
22
|
+
J: [0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0c],
|
|
23
|
+
K: [0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11],
|
|
24
|
+
L: [0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f],
|
|
25
|
+
M: [0x11, 0x1b, 0x15, 0x15, 0x11, 0x11, 0x11],
|
|
26
|
+
N: [0x11, 0x19, 0x19, 0x15, 0x13, 0x13, 0x11],
|
|
27
|
+
O: [0x0e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e],
|
|
28
|
+
P: [0x1e, 0x11, 0x11, 0x1e, 0x10, 0x10, 0x10],
|
|
29
|
+
Q: [0x0e, 0x11, 0x11, 0x11, 0x15, 0x13, 0x0d],
|
|
30
|
+
R: [0x1e, 0x11, 0x11, 0x1e, 0x14, 0x12, 0x11],
|
|
31
|
+
S: [0x0f, 0x10, 0x10, 0x0e, 0x01, 0x01, 0x1e],
|
|
32
|
+
T: [0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04],
|
|
33
|
+
U: [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e],
|
|
34
|
+
V: [0x11, 0x11, 0x11, 0x11, 0x11, 0x0a, 0x04],
|
|
35
|
+
W: [0x11, 0x11, 0x11, 0x15, 0x15, 0x1b, 0x11],
|
|
36
|
+
X: [0x11, 0x11, 0x0a, 0x04, 0x0a, 0x11, 0x11],
|
|
37
|
+
Y: [0x11, 0x11, 0x0a, 0x04, 0x04, 0x04, 0x04],
|
|
38
|
+
Z: [0x1f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1f],
|
|
39
|
+
'0': [0x0e, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0e],
|
|
40
|
+
'1': [0x04, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x0e],
|
|
41
|
+
'2': [0x0e, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1f],
|
|
42
|
+
'3': [0x1f, 0x02, 0x04, 0x06, 0x01, 0x11, 0x0e],
|
|
43
|
+
'4': [0x02, 0x06, 0x0a, 0x12, 0x1f, 0x02, 0x02],
|
|
44
|
+
'5': [0x1f, 0x10, 0x1e, 0x01, 0x01, 0x11, 0x0e],
|
|
45
|
+
'6': [0x06, 0x08, 0x10, 0x1e, 0x11, 0x11, 0x0e],
|
|
46
|
+
'7': [0x1f, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08],
|
|
47
|
+
'8': [0x0e, 0x11, 0x11, 0x0e, 0x11, 0x11, 0x0e],
|
|
48
|
+
'9': [0x0e, 0x11, 0x11, 0x0f, 0x01, 0x02, 0x0c],
|
|
49
|
+
' ': [0, 0, 0, 0, 0, 0, 0],
|
|
50
|
+
_: [0, 0, 0, 0, 0, 0, 0x1f],
|
|
51
|
+
'-': [0, 0, 0, 0x1f, 0, 0, 0],
|
|
52
|
+
'.': [0, 0, 0, 0, 0, 0x0c, 0x0c],
|
|
53
|
+
',': [0, 0, 0, 0, 0x0c, 0x0c, 0x04],
|
|
54
|
+
':': [0, 0x0c, 0x0c, 0, 0x0c, 0x0c, 0],
|
|
55
|
+
'/': [0x01, 0x02, 0x02, 0x04, 0x08, 0x08, 0x10],
|
|
56
|
+
'(': [0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02],
|
|
57
|
+
')': [0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08],
|
|
58
|
+
'!': [0x04, 0x04, 0x04, 0x04, 0x04, 0, 0x04],
|
|
59
|
+
'+': [0, 0x04, 0x04, 0x1f, 0x04, 0x04, 0],
|
|
60
|
+
'=': [0, 0, 0x1f, 0, 0x1f, 0, 0],
|
|
61
|
+
'<': [0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02],
|
|
62
|
+
'>': [0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08],
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const GLYPH_W = 5;
|
|
66
|
+
export const GLYPH_H = 7;
|
|
67
|
+
|
|
68
|
+
/** Width in pixels of `text` drawn at `scale` with a one-column gap. */
|
|
69
|
+
export function textWidth(text: string, scale: number): number {
|
|
70
|
+
if (!text.length) return 0;
|
|
71
|
+
return (text.length * (GLYPH_W + 1) - 1) * scale;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Rasterise `text` by calling `plot(x, y)` for every lit pixel, with the top
|
|
76
|
+
* left of the first glyph at (x0, y0). Unknown characters draw as a full block
|
|
77
|
+
* so a typo is loud rather than invisible.
|
|
78
|
+
*/
|
|
79
|
+
export function drawText(
|
|
80
|
+
text: string,
|
|
81
|
+
x0: number,
|
|
82
|
+
y0: number,
|
|
83
|
+
scale: number,
|
|
84
|
+
plot: (x: number, y: number) => void,
|
|
85
|
+
): void {
|
|
86
|
+
let cursor = x0;
|
|
87
|
+
for (const ch of text.toUpperCase()) {
|
|
88
|
+
const glyph = GLYPHS[ch] ?? [0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f];
|
|
89
|
+
for (let row = 0; row < GLYPH_H; row++) {
|
|
90
|
+
for (let col = 0; col < GLYPH_W; col++) {
|
|
91
|
+
if (!(glyph[row] & (1 << (GLYPH_W - 1 - col)))) continue;
|
|
92
|
+
for (let sy = 0; sy < scale; sy++) {
|
|
93
|
+
for (let sx = 0; sx < scale; sx++) {
|
|
94
|
+
plot(cursor + col * scale + sx, y0 + row * scale + sy);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
cursor += (GLYPH_W + 1) * scale;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Measure a cut's contact depth from its plates.
|
|
4
|
+
*
|
|
5
|
+
* bun tools/measure_contact_depth.ts <manifest.json> <massSlot> <againstSlot>
|
|
6
|
+
*
|
|
7
|
+
* The rule it makes mechanical: inward travel goes at most until the moving mass
|
|
8
|
+
* touches the part that occludes it. That turns the deepest inward amplitude
|
|
9
|
+
* from a number somebody picks into a measured fact.
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ The two slot names are REQUIRED and the tool has no defaults for them. Which
|
|
12
|
+
* plate is the mass and which is the occluder is a fact about one cut's anatomy,
|
|
13
|
+
* and a default here would quietly measure the wrong pair on the next cut and
|
|
14
|
+
* still print a plausible number.
|
|
15
|
+
*
|
|
16
|
+
* The result goes into the manifest as `stroke.contact_depth`. It is not computed
|
|
17
|
+
* at build time on purpose — the compiler never re-measures art, the same
|
|
18
|
+
* division that keeps `mesh.center` a measured manifest number.
|
|
19
|
+
*
|
|
20
|
+
* Output includes the two-sided proof the depth has to satisfy: ZERO overlapping
|
|
21
|
+
* body pixels at the depth, and MORE THAN ZERO one pixel past it. A depth with no
|
|
22
|
+
* overlap one pixel past is not "touching", it is just short.
|
|
23
|
+
*/
|
|
24
|
+
import { readFileSync } from 'node:fs';
|
|
25
|
+
import { dirname, resolve } from 'node:path';
|
|
26
|
+
import { readPlate } from './plate.ts';
|
|
27
|
+
import { BODY_ALPHA, measureContactDepth } from './contact.ts';
|
|
28
|
+
|
|
29
|
+
interface Part {
|
|
30
|
+
slot: string;
|
|
31
|
+
image?: string;
|
|
32
|
+
offset: [number, number];
|
|
33
|
+
size?: [number, number];
|
|
34
|
+
}
|
|
35
|
+
interface Manifest {
|
|
36
|
+
crop: { w: number; h: number };
|
|
37
|
+
insertion?: [number, number];
|
|
38
|
+
axis?: { deg: number };
|
|
39
|
+
stroke?: { contact_depth?: number };
|
|
40
|
+
parts: Part[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const [manifestArg, massSlot, againstSlot] = process.argv.slice(2);
|
|
44
|
+
if (!manifestArg || !massSlot || !againstSlot) {
|
|
45
|
+
console.error('usage: bun tools/measure_contact_depth.ts <manifest.json> <massSlot> <againstSlot>');
|
|
46
|
+
console.error(' massSlot the part that advances');
|
|
47
|
+
console.error(' againstSlot the part it must not pass through');
|
|
48
|
+
process.exit(2);
|
|
49
|
+
}
|
|
50
|
+
const manifestPath = resolve(manifestArg);
|
|
51
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as Manifest;
|
|
52
|
+
const dir = dirname(manifestPath);
|
|
53
|
+
|
|
54
|
+
if (!manifest.axis) {
|
|
55
|
+
console.error('manifest has no `axis`; the contact depth is a distance ALONG the axis and cannot be measured without it');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const partOf = (slot: string): Part => {
|
|
59
|
+
const part = manifest.parts.find((p) => p.slot === slot);
|
|
60
|
+
if (!part?.image) throw new Error(`manifest has no part with an image for slot "${slot}"`);
|
|
61
|
+
return part;
|
|
62
|
+
};
|
|
63
|
+
const load = (slot: string) => {
|
|
64
|
+
const part = partOf(slot);
|
|
65
|
+
return { part, plate: readPlate(resolve(dir, part.image!)) };
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const mass = load(massSlot);
|
|
69
|
+
const against = load(againstSlot);
|
|
70
|
+
const rad = (manifest.axis.deg * Math.PI) / 180;
|
|
71
|
+
const inward: [number, number] = [Math.cos(rad), Math.sin(rad)];
|
|
72
|
+
|
|
73
|
+
const result = measureContactDepth(
|
|
74
|
+
{ plate: mass.plate, offset: mass.part.offset },
|
|
75
|
+
{ plate: against.plate, offset: against.part.offset },
|
|
76
|
+
inward,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
console.log(`contact depth for ${manifestPath}`);
|
|
80
|
+
console.log(` axis ${manifest.axis.deg} deg (screen, y down) -> inward unit [${inward.map((v) => v.toFixed(4)).join(', ')}]`);
|
|
81
|
+
console.log(` mass ${massSlot.padEnd(12)} ${mass.plate.width}x${mass.plate.height} at ${JSON.stringify(mass.part.offset)} ${result.massPixels} body px`);
|
|
82
|
+
console.log(` against ${againstSlot.padEnd(12)} ${against.plate.width}x${against.plate.height} at ${JSON.stringify(against.part.offset)} ${result.againstPixels} body px`);
|
|
83
|
+
console.log(` alpha threshold ${result.alphaThreshold} of 255`);
|
|
84
|
+
const expected = result.touches ? result.depth : null;
|
|
85
|
+
if (!result.touches) {
|
|
86
|
+
console.log(` DEPTH none — scanned to ${result.depth}px without the footprints ever meeting`);
|
|
87
|
+
console.log(' along this axis the masses never touch, so the rule imposes no ceiling');
|
|
88
|
+
} else {
|
|
89
|
+
console.log(` DEPTH ${result.depth} px inward`);
|
|
90
|
+
console.log(` overlap at depth ${result.overlapAtDepth} (must be 0)`);
|
|
91
|
+
console.log(` overlap one px past ${result.overlapPastDepth} (must be > 0, or the depth is short rather than touching)`);
|
|
92
|
+
console.log(` first contact ${JSON.stringify(result.contactPoint)} (crop px)`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const declared = manifest.stroke?.contact_depth ?? null;
|
|
96
|
+
if ('contact_depth' in (manifest.stroke ?? {})) {
|
|
97
|
+
const agrees = declared === expected;
|
|
98
|
+
console.log(` manifest says ${JSON.stringify(declared)} -> ${agrees ? 'agrees' : 'DISAGREES with the plates'}`);
|
|
99
|
+
if (!agrees) process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
if (result.touches && (result.overlapAtDepth !== 0 || result.overlapPastDepth === 0)) {
|
|
102
|
+
console.error(' the two-sided proof failed: this is not a tangency');
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
console.log(result.touches ? ' ok — tangent at the depth, overlapping one pixel past it' : ' ok — no ceiling to declare');
|