@franzenzenhofer/asanakit 0.1.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 +153 -0
- package/dist/anatomy/muscles.d.ts +55 -0
- package/dist/anatomy/muscles.d.ts.map +1 -0
- package/dist/anatomy/muscles.js +79 -0
- package/dist/anatomy/muscles.js.map +1 -0
- package/dist/anatomy/validate.d.ts +11 -0
- package/dist/anatomy/validate.d.ts.map +1 -0
- package/dist/anatomy/validate.js +94 -0
- package/dist/anatomy/validate.js.map +1 -0
- package/dist/cli/commands/export.d.ts +3 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +45 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/info.d.ts +3 -0
- package/dist/cli/commands/info.d.ts.map +1 -0
- package/dist/cli/commands/info.js +101 -0
- package/dist/cli/commands/info.js.map +1 -0
- package/dist/cli/commands/render.d.ts +3 -0
- package/dist/cli/commands/render.d.ts.map +1 -0
- package/dist/cli/commands/render.js +103 -0
- package/dist/cli/commands/render.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +31 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/resolve.d.ts +12 -0
- package/dist/cli/resolve.d.ts.map +1 -0
- package/dist/cli/resolve.js +46 -0
- package/dist/cli/resolve.js.map +1 -0
- package/dist/core/angles.d.ts +12 -0
- package/dist/core/angles.d.ts.map +1 -0
- package/dist/core/angles.js +27 -0
- package/dist/core/angles.js.map +1 -0
- package/dist/core/rig.d.ts +8 -0
- package/dist/core/rig.d.ts.map +1 -0
- package/dist/core/rig.js +97 -0
- package/dist/core/rig.js.map +1 -0
- package/dist/core/skeleton.d.ts +17 -0
- package/dist/core/skeleton.d.ts.map +1 -0
- package/dist/core/skeleton.js +144 -0
- package/dist/core/skeleton.js.map +1 -0
- package/dist/core/types.d.ts +105 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +47 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/vec2.d.ts +19 -0
- package/dist/core/vec2.d.ts.map +1 -0
- package/dist/core/vec2.js +41 -0
- package/dist/core/vec2.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/library/index.d.ts +27 -0
- package/dist/library/index.d.ts.map +1 -0
- package/dist/library/index.js +75 -0
- package/dist/library/index.js.map +1 -0
- package/dist/model/index.d.ts +4 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/index.js +4 -0
- package/dist/model/index.js.map +1 -0
- package/dist/model/parse.d.ts +12 -0
- package/dist/model/parse.d.ts.map +1 -0
- package/dist/model/parse.js +43 -0
- package/dist/model/parse.js.map +1 -0
- package/dist/model/pose.d.ts +11 -0
- package/dist/model/pose.d.ts.map +1 -0
- package/dist/model/pose.js +26 -0
- package/dist/model/pose.js.map +1 -0
- package/dist/model/schema.d.ts +1122 -0
- package/dist/model/schema.d.ts.map +1 -0
- package/dist/model/schema.js +178 -0
- package/dist/model/schema.js.map +1 -0
- package/dist/render/anatomy.d.ts +10 -0
- package/dist/render/anatomy.d.ts.map +1 -0
- package/dist/render/anatomy.js +77 -0
- package/dist/render/anatomy.js.map +1 -0
- package/dist/render/annotations.d.ts +9 -0
- package/dist/render/annotations.d.ts.map +1 -0
- package/dist/render/annotations.js +185 -0
- package/dist/render/annotations.js.map +1 -0
- package/dist/render/context.d.ts +16 -0
- package/dist/render/context.d.ts.map +1 -0
- package/dist/render/context.js +2 -0
- package/dist/render/context.js.map +1 -0
- package/dist/render/figure.d.ts +8 -0
- package/dist/render/figure.d.ts.map +1 -0
- package/dist/render/figure.js +138 -0
- package/dist/render/figure.js.map +1 -0
- package/dist/render/index.d.ts +7 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +7 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/project.d.ts +18 -0
- package/dist/render/project.d.ts.map +1 -0
- package/dist/render/project.js +35 -0
- package/dist/render/project.js.map +1 -0
- package/dist/render/props.d.ts +9 -0
- package/dist/render/props.d.ts.map +1 -0
- package/dist/render/props.js +178 -0
- package/dist/render/props.js.map +1 -0
- package/dist/render/raster.d.ts +19 -0
- package/dist/render/raster.d.ts.map +1 -0
- package/dist/render/raster.js +39 -0
- package/dist/render/raster.js.map +1 -0
- package/dist/render/scene.d.ts +26 -0
- package/dist/render/scene.d.ts.map +1 -0
- package/dist/render/scene.js +144 -0
- package/dist/render/scene.js.map +1 -0
- package/dist/render/sheet.d.ts +20 -0
- package/dist/render/sheet.d.ts.map +1 -0
- package/dist/render/sheet.js +74 -0
- package/dist/render/sheet.js.map +1 -0
- package/dist/render/styles.d.ts +77 -0
- package/dist/render/styles.d.ts.map +1 -0
- package/dist/render/styles.js +122 -0
- package/dist/render/styles.js.map +1 -0
- package/dist/render/svg.d.ts +19 -0
- package/dist/render/svg.d.ts.map +1 -0
- package/dist/render/svg.js +40 -0
- package/dist/render/svg.js.map +1 -0
- package/dist/standards/keypoints.d.ts +31 -0
- package/dist/standards/keypoints.d.ts.map +1 -0
- package/dist/standards/keypoints.js +118 -0
- package/dist/standards/keypoints.js.map +1 -0
- package/docs/AUTHORING.md +144 -0
- package/package.json +94 -0
- package/poses/surf/bottom-turn.pose.yaml +47 -0
- package/poses/surf/cutback.pose.yaml +47 -0
- package/poses/surf/duck-dive.pose.yaml +47 -0
- package/poses/surf/noseride.pose.yaml +48 -0
- package/poses/surf/paddling.pose.yaml +48 -0
- package/poses/surf/pop-up.pose.yaml +47 -0
- package/poses/surf/takeoff.pose.yaml +47 -0
- package/poses/surf/tube-stance.pose.yaml +47 -0
- package/poses/yoga/ashtanga/adho-mukha-svanasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/ardha-uttanasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/baddha-konasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/balasana.pose.yaml +43 -0
- package/poses/yoga/ashtanga/chaturanga-dandasana.pose.yaml +41 -0
- package/poses/yoga/ashtanga/dandasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/halasana.pose.yaml +43 -0
- package/poses/yoga/ashtanga/janu-sirsasana-a.pose.yaml +42 -0
- package/poses/yoga/ashtanga/karnapidasana.pose.yaml +43 -0
- package/poses/yoga/ashtanga/marichyasana-a.pose.yaml +42 -0
- package/poses/yoga/ashtanga/marichyasana-c.pose.yaml +42 -0
- package/poses/yoga/ashtanga/matsyasana.pose.yaml +43 -0
- package/poses/yoga/ashtanga/navasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/padahastasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/padangusthasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/padmasana.pose.yaml +43 -0
- package/poses/yoga/ashtanga/parsvottanasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/paschimottanasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/prasarita-padottanasana-a.pose.yaml +46 -0
- package/poses/yoga/ashtanga/prasarita-padottanasana-c.pose.yaml +46 -0
- package/poses/yoga/ashtanga/primary.seq.yaml +74 -0
- package/poses/yoga/ashtanga/purvottanasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/salamba-sarvangasana.pose.yaml +43 -0
- package/poses/yoga/ashtanga/samasthiti.pose.yaml +29 -0
- package/poses/yoga/ashtanga/savasana.pose.yaml +43 -0
- package/poses/yoga/ashtanga/setu-bandhasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/sirsasana.pose.yaml +43 -0
- package/poses/yoga/ashtanga/supta-padangusthasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/upavistha-konasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/urdhva-dhanurasana.pose.yaml +43 -0
- package/poses/yoga/ashtanga/urdhva-hastasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/urdhva-mukha-svanasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/utkatasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/uttanasana.pose.yaml +42 -0
- package/poses/yoga/ashtanga/utthita-parsvakonasana.pose.yaml +44 -0
- package/poses/yoga/ashtanga/utthita-trikonasana.pose.yaml +44 -0
- package/poses/yoga/ashtanga/virabhadrasana-a.pose.yaml +42 -0
- package/poses/yoga/ashtanga/virabhadrasana-b.pose.yaml +42 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { DEFAULT_RIG } from '../core/rig.js';
|
|
2
|
+
import { solveSkeleton } from '../core/skeleton.js';
|
|
3
|
+
import { resolveFigure } from '../model/index.js';
|
|
4
|
+
import { renderMuscles } from './anatomy.js';
|
|
5
|
+
import { annotationsBounds, arrowMarker, renderAnnotations } from './annotations.js';
|
|
6
|
+
import { renderFigure } from './figure.js';
|
|
7
|
+
import { fitProjection, padBounds, unionBounds } from './project.js';
|
|
8
|
+
import { propsBounds, renderProps } from './props.js';
|
|
9
|
+
import { resolveStyle } from './styles.js';
|
|
10
|
+
import { el, group, serialize, textEl } from './svg.js';
|
|
11
|
+
export const DEFAULT_WIDTH = 600;
|
|
12
|
+
export const DEFAULT_HEIGHT = 800;
|
|
13
|
+
const TITLE_BAND = 2.4;
|
|
14
|
+
const CAPTION_LINE = 1.55;
|
|
15
|
+
const shiftProjection = (proj, dy) => ({
|
|
16
|
+
s: proj.s,
|
|
17
|
+
p: (v) => {
|
|
18
|
+
const [x, y] = proj.p(v);
|
|
19
|
+
return [x, y + dy];
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
/** Everything that must be visible: the figure, its props and its annotations. */
|
|
23
|
+
export const contentBounds = (pose, skeleton, style) => {
|
|
24
|
+
const headPad = Math.max(style.head.rx, style.head.ry) * skeleton.scale;
|
|
25
|
+
let bounds = padBounds(skeleton.bounds, headPad);
|
|
26
|
+
const props = propsBounds(pose.props, skeleton);
|
|
27
|
+
if (props !== null)
|
|
28
|
+
bounds = unionBounds(bounds, props);
|
|
29
|
+
const annotations = annotationsBounds(pose.annotations, skeleton);
|
|
30
|
+
if (annotations !== null)
|
|
31
|
+
bounds = unionBounds(bounds, annotations);
|
|
32
|
+
return padBounds(bounds, style.padding);
|
|
33
|
+
};
|
|
34
|
+
const styleFor = (options) => {
|
|
35
|
+
const base = resolveStyle(options.style ?? 'stick', options.styleOverride ?? {});
|
|
36
|
+
if (options.muscles === undefined)
|
|
37
|
+
return base;
|
|
38
|
+
return { ...base, muscles: { ...base.muscles, show: options.muscles } };
|
|
39
|
+
};
|
|
40
|
+
const layoutFor = (pose, options, style) => {
|
|
41
|
+
const width = options.width ?? DEFAULT_WIDTH;
|
|
42
|
+
const height = options.height ?? DEFAULT_HEIGHT;
|
|
43
|
+
const titleSize = style.text.titleSize * height;
|
|
44
|
+
const captionSize = style.text.captionSize * height;
|
|
45
|
+
const cues = options.caption === true ? pose.cues : [];
|
|
46
|
+
return {
|
|
47
|
+
width,
|
|
48
|
+
height,
|
|
49
|
+
titleSize,
|
|
50
|
+
captionSize,
|
|
51
|
+
cues,
|
|
52
|
+
titleBand: options.title === true ? titleSize * TITLE_BAND : 0,
|
|
53
|
+
captionBand: cues.length === 0 ? 0 : captionSize * (1 + cues.length * CAPTION_LINE),
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Shrink a title until it fits the canvas. A clipped pose name is a broken sheet,
|
|
58
|
+
* and "Parivrtta Parsvakonasana" is not a short word.
|
|
59
|
+
*/
|
|
60
|
+
const AVG_GLYPH_WIDTH = 0.56;
|
|
61
|
+
const TITLE_SAFE_WIDTH = 0.84;
|
|
62
|
+
const fitText = (text, size, width) => Math.min(size, (width * TITLE_SAFE_WIDTH) / (Math.max(text.length, 1) * AVG_GLYPH_WIDTH));
|
|
63
|
+
const titleBlock = (pose, layout, style) => {
|
|
64
|
+
const size = fitText(pose.name, layout.titleSize, layout.width);
|
|
65
|
+
return group({ 'data-layer': 'title' }, [
|
|
66
|
+
textEl('text', {
|
|
67
|
+
x: layout.width / 2,
|
|
68
|
+
y: size * 1.15,
|
|
69
|
+
'text-anchor': 'middle',
|
|
70
|
+
fill: style.text.color,
|
|
71
|
+
'font-family': style.text.fontFamily,
|
|
72
|
+
'font-size': size,
|
|
73
|
+
'font-weight': 600,
|
|
74
|
+
}, pose.name),
|
|
75
|
+
...(pose.sanskrit === undefined
|
|
76
|
+
? []
|
|
77
|
+
: [
|
|
78
|
+
textEl('text', {
|
|
79
|
+
x: layout.width / 2,
|
|
80
|
+
y: layout.titleSize * 2,
|
|
81
|
+
'text-anchor': 'middle',
|
|
82
|
+
fill: style.text.muted,
|
|
83
|
+
'font-family': style.text.fontFamily,
|
|
84
|
+
'font-size': fitText(pose.sanskrit, layout.titleSize * 0.55, layout.width),
|
|
85
|
+
'font-style': 'italic',
|
|
86
|
+
}, pose.sanskrit),
|
|
87
|
+
]),
|
|
88
|
+
]);
|
|
89
|
+
};
|
|
90
|
+
const captionBlock = (layout, style) => {
|
|
91
|
+
const size = layout.captionSize;
|
|
92
|
+
const top = layout.height - layout.captionBand;
|
|
93
|
+
return group({ 'data-layer': 'caption' }, layout.cues.map((cue, i) => textEl('text', {
|
|
94
|
+
x: layout.width / 2,
|
|
95
|
+
y: top + size * (1 + i * CAPTION_LINE),
|
|
96
|
+
'text-anchor': 'middle',
|
|
97
|
+
fill: style.text.muted,
|
|
98
|
+
'font-family': style.text.fontFamily,
|
|
99
|
+
'font-size': size,
|
|
100
|
+
}, cue)));
|
|
101
|
+
};
|
|
102
|
+
const compact = (nodes) => nodes.filter((n) => n !== null);
|
|
103
|
+
const layers = (pose, ctx) => compact([
|
|
104
|
+
renderProps(ctx, pose.props),
|
|
105
|
+
renderMuscles(ctx, pose.muscles.engaged, pose.muscles.stretched),
|
|
106
|
+
renderFigure(ctx),
|
|
107
|
+
renderAnnotations(ctx, pose.annotations),
|
|
108
|
+
]);
|
|
109
|
+
export const renderSvgNode = (pose, options = {}) => {
|
|
110
|
+
const style = styleFor(options);
|
|
111
|
+
const layout = layoutFor(pose, options, style);
|
|
112
|
+
const { width, height } = layout;
|
|
113
|
+
const skeleton = solveSkeleton(resolveFigure(pose.figure), options.rig ?? DEFAULT_RIG);
|
|
114
|
+
const content = contentBounds(pose, skeleton, style);
|
|
115
|
+
const stage = Math.max(height - layout.titleBand - layout.captionBand, 1);
|
|
116
|
+
const ctx = {
|
|
117
|
+
skeleton,
|
|
118
|
+
content,
|
|
119
|
+
style,
|
|
120
|
+
proj: shiftProjection(fitProjection(content, width, stage), layout.titleBand),
|
|
121
|
+
};
|
|
122
|
+
const background = options.background ?? style.background;
|
|
123
|
+
return el('svg', {
|
|
124
|
+
xmlns: 'http://www.w3.org/2000/svg',
|
|
125
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
126
|
+
width,
|
|
127
|
+
height,
|
|
128
|
+
'data-pose': pose.id,
|
|
129
|
+
'data-style': style.id,
|
|
130
|
+
role: 'img',
|
|
131
|
+
'aria-label': `${pose.name}${pose.sanskrit === undefined ? '' : ` (${pose.sanskrit})`}`,
|
|
132
|
+
}, [
|
|
133
|
+
arrowMarker(style.annotation.accent),
|
|
134
|
+
...(background === 'none'
|
|
135
|
+
? []
|
|
136
|
+
: [el('rect', { 'data-layer': 'background', x: 0, y: 0, width, height, fill: background })]),
|
|
137
|
+
...(options.title === true ? [titleBlock(pose, layout, style)] : []),
|
|
138
|
+
...layers(pose, ctx),
|
|
139
|
+
...(layout.cues.length === 0 ? [] : [captionBlock(layout, style)]),
|
|
140
|
+
]);
|
|
141
|
+
};
|
|
142
|
+
/** Render a pose to a standalone, deterministic SVG document. */
|
|
143
|
+
export const renderSvg = (pose, options = {}) => serialize(renderSvgNode(pose, options));
|
|
144
|
+
//# sourceMappingURL=scene.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene.js","sourceRoot":"","sources":["../../src/render/scene.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PoseSpec } from '../model/index.js';
|
|
2
|
+
import { type RenderOptions } from './scene.js';
|
|
3
|
+
import { type SvgNode } from './svg.js';
|
|
4
|
+
export interface SheetOptions extends RenderOptions {
|
|
5
|
+
readonly columns?: number;
|
|
6
|
+
readonly cellWidth?: number;
|
|
7
|
+
readonly cellHeight?: number;
|
|
8
|
+
readonly sheetTitle?: string;
|
|
9
|
+
/** Print the sequence position on each cell - what a practice sheet needs. */
|
|
10
|
+
readonly numbered?: boolean;
|
|
11
|
+
readonly gutter?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A contact sheet is just nested <svg> elements: each pose already renders into
|
|
15
|
+
* its own viewBox, so laying out a whole series is a translate per cell. No
|
|
16
|
+
* packing library needed while the cells are a uniform size.
|
|
17
|
+
*/
|
|
18
|
+
export declare const renderSheetNode: (poses: readonly PoseSpec[], options?: SheetOptions) => SvgNode;
|
|
19
|
+
export declare const renderSheet: (poses: readonly PoseSpec[], options?: SheetOptions) => string;
|
|
20
|
+
//# sourceMappingURL=sheet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../../src/render/sheet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/D,OAAO,EAAgC,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAEtE,MAAM,WAAW,YAAa,SAAQ,aAAa;IACjD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,SAAS,QAAQ,EAAE,EAAE,UAAS,YAAiB,KAAG,OAgFxF,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,SAAS,QAAQ,EAAE,EAAE,UAAS,YAAiB,KAAG,MACzC,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { renderSvgNode } from './scene.js';
|
|
2
|
+
import { resolveStyle } from './styles.js';
|
|
3
|
+
import { el, group, serialize, textEl } from './svg.js';
|
|
4
|
+
const DEFAULTS = { columns: 6, cellWidth: 260, cellHeight: 340, gutter: 0 };
|
|
5
|
+
/**
|
|
6
|
+
* A contact sheet is just nested <svg> elements: each pose already renders into
|
|
7
|
+
* its own viewBox, so laying out a whole series is a translate per cell. No
|
|
8
|
+
* packing library needed while the cells are a uniform size.
|
|
9
|
+
*/
|
|
10
|
+
export const renderSheetNode = (poses, options = {}) => {
|
|
11
|
+
const columns = Math.max(1, options.columns ?? DEFAULTS.columns);
|
|
12
|
+
const cw = options.cellWidth ?? DEFAULTS.cellWidth;
|
|
13
|
+
const ch = options.cellHeight ?? DEFAULTS.cellHeight;
|
|
14
|
+
const gutter = options.gutter ?? DEFAULTS.gutter;
|
|
15
|
+
const style = resolveStyle(options.style ?? 'stick', options.styleOverride ?? {});
|
|
16
|
+
const rows = Math.max(1, Math.ceil(poses.length / columns));
|
|
17
|
+
const titleSize = options.sheetTitle === undefined ? 0 : Math.round(ch * 0.11);
|
|
18
|
+
const titleBand = titleSize === 0 ? 0 : titleSize * 2.2;
|
|
19
|
+
const width = columns * cw + (columns - 1) * gutter;
|
|
20
|
+
const height = rows * ch + (rows - 1) * gutter + titleBand;
|
|
21
|
+
const cells = poses.map((pose, i) => {
|
|
22
|
+
const col = i % columns;
|
|
23
|
+
const row = Math.floor(i / columns);
|
|
24
|
+
const x = col * (cw + gutter);
|
|
25
|
+
const y = titleBand + row * (ch + gutter);
|
|
26
|
+
const inner = renderSvgNode(pose, {
|
|
27
|
+
...options,
|
|
28
|
+
width: cw,
|
|
29
|
+
height: ch,
|
|
30
|
+
background: options.background ?? 'none',
|
|
31
|
+
title: options.title ?? true,
|
|
32
|
+
});
|
|
33
|
+
return group({ transform: `translate(${x} ${y})`, 'data-cell': String(i + 1) }, [
|
|
34
|
+
inner,
|
|
35
|
+
...(options.numbered === true
|
|
36
|
+
? [
|
|
37
|
+
textEl('text', {
|
|
38
|
+
x: cw * 0.04,
|
|
39
|
+
y: ch * 0.06,
|
|
40
|
+
fill: style.text.muted,
|
|
41
|
+
'font-family': style.text.fontFamily,
|
|
42
|
+
'font-size': ch * 0.038,
|
|
43
|
+
'font-weight': 600,
|
|
44
|
+
}, String(i + 1)),
|
|
45
|
+
]
|
|
46
|
+
: []),
|
|
47
|
+
]);
|
|
48
|
+
});
|
|
49
|
+
return el('svg', {
|
|
50
|
+
xmlns: 'http://www.w3.org/2000/svg',
|
|
51
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
52
|
+
width,
|
|
53
|
+
height,
|
|
54
|
+
'data-sheet': poses.length,
|
|
55
|
+
}, [
|
|
56
|
+
el('rect', { x: 0, y: 0, width, height, fill: options.background ?? style.background }),
|
|
57
|
+
...(options.sheetTitle === undefined
|
|
58
|
+
? []
|
|
59
|
+
: [
|
|
60
|
+
textEl('text', {
|
|
61
|
+
x: width / 2,
|
|
62
|
+
y: titleSize * 1.4,
|
|
63
|
+
'text-anchor': 'middle',
|
|
64
|
+
fill: style.text.color,
|
|
65
|
+
'font-family': style.text.fontFamily,
|
|
66
|
+
'font-size': titleSize,
|
|
67
|
+
'font-weight': 700,
|
|
68
|
+
}, options.sheetTitle),
|
|
69
|
+
]),
|
|
70
|
+
...cells,
|
|
71
|
+
]);
|
|
72
|
+
};
|
|
73
|
+
export const renderSheet = (poses, options = {}) => serialize(renderSheetNode(poses, options));
|
|
74
|
+
//# sourceMappingURL=sheet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet.js","sourceRoot":"","sources":["../../src/render/sheet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Style tokens. Everything the renderer draws reads its geometry and colour
|
|
3
|
+
* from here, so a new look is a data change, never a code change. All sizes are
|
|
4
|
+
* in stature units (1.0 = figure height) and scale with the canvas.
|
|
5
|
+
*/
|
|
6
|
+
export interface Style {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly label: string;
|
|
9
|
+
readonly background: string;
|
|
10
|
+
readonly padding: number;
|
|
11
|
+
readonly figure: {
|
|
12
|
+
readonly stroke: string;
|
|
13
|
+
readonly strokeWidth: number;
|
|
14
|
+
readonly lineCap: 'round' | 'butt' | 'square';
|
|
15
|
+
readonly joints: 'none' | 'dots';
|
|
16
|
+
readonly jointRadius: number;
|
|
17
|
+
readonly torsoWidth: number;
|
|
18
|
+
readonly fill: string;
|
|
19
|
+
readonly farOpacity: number;
|
|
20
|
+
};
|
|
21
|
+
readonly head: {
|
|
22
|
+
readonly shape: 'ellipse' | 'circle' | 'none';
|
|
23
|
+
readonly rx: number;
|
|
24
|
+
readonly ry: number;
|
|
25
|
+
readonly fill: string;
|
|
26
|
+
readonly stroke: string;
|
|
27
|
+
readonly strokeWidth: number;
|
|
28
|
+
};
|
|
29
|
+
readonly muscles: {
|
|
30
|
+
readonly show: boolean;
|
|
31
|
+
readonly base: string;
|
|
32
|
+
readonly opacity: number;
|
|
33
|
+
readonly engaged: string;
|
|
34
|
+
readonly stretched: string;
|
|
35
|
+
readonly outline: string;
|
|
36
|
+
readonly outlineWidth: number;
|
|
37
|
+
};
|
|
38
|
+
readonly props: {
|
|
39
|
+
readonly stroke: string;
|
|
40
|
+
readonly fill: string;
|
|
41
|
+
readonly strokeWidth: number;
|
|
42
|
+
};
|
|
43
|
+
readonly annotation: {
|
|
44
|
+
readonly stroke: string;
|
|
45
|
+
readonly strokeWidth: number;
|
|
46
|
+
readonly accent: string;
|
|
47
|
+
readonly color: string;
|
|
48
|
+
readonly fontFamily: string;
|
|
49
|
+
readonly fontSize: number;
|
|
50
|
+
readonly dash: string;
|
|
51
|
+
};
|
|
52
|
+
readonly text: {
|
|
53
|
+
readonly color: string;
|
|
54
|
+
readonly muted: string;
|
|
55
|
+
readonly fontFamily: string;
|
|
56
|
+
readonly titleSize: number;
|
|
57
|
+
readonly captionSize: number;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export type StyleOverride = {
|
|
61
|
+
readonly [K in keyof Style]?: Style[K] extends object ? Partial<Style[K]> : Style[K];
|
|
62
|
+
};
|
|
63
|
+
export declare const STYLES: {
|
|
64
|
+
readonly stick: Style;
|
|
65
|
+
readonly anatomy: Style;
|
|
66
|
+
readonly silhouette: Style;
|
|
67
|
+
readonly blueprint: Style;
|
|
68
|
+
readonly ink: Style;
|
|
69
|
+
readonly poster: Style;
|
|
70
|
+
readonly minimal: Style;
|
|
71
|
+
};
|
|
72
|
+
export type StyleId = keyof typeof STYLES;
|
|
73
|
+
export declare const STYLE_IDS: StyleId[];
|
|
74
|
+
export declare const isStyleId: (value: string) => value is StyleId;
|
|
75
|
+
/** Merge a partial override one level deep - deep enough for the token tree, shallow enough to stay predictable. */
|
|
76
|
+
export declare const resolveStyle: (id?: StyleId, override?: StyleOverride) => Style;
|
|
77
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/render/styles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
const SANS = 'Helvetica Neue, Helvetica, Arial, sans-serif';
|
|
2
|
+
const stick = {
|
|
3
|
+
id: 'stick',
|
|
4
|
+
label: 'Stick figure',
|
|
5
|
+
background: '#ffffff',
|
|
6
|
+
padding: 0.12,
|
|
7
|
+
figure: {
|
|
8
|
+
stroke: '#111111',
|
|
9
|
+
strokeWidth: 0.022,
|
|
10
|
+
lineCap: 'round',
|
|
11
|
+
joints: 'dots',
|
|
12
|
+
jointRadius: 0.014,
|
|
13
|
+
torsoWidth: 0,
|
|
14
|
+
fill: 'none',
|
|
15
|
+
farOpacity: 0.45,
|
|
16
|
+
},
|
|
17
|
+
head: { shape: 'ellipse', rx: 0.046, ry: 0.062, fill: '#ffffff', stroke: '#111111', strokeWidth: 0.02 },
|
|
18
|
+
muscles: {
|
|
19
|
+
show: false,
|
|
20
|
+
base: '#e6ded6',
|
|
21
|
+
opacity: 1,
|
|
22
|
+
engaged: '#d1495b',
|
|
23
|
+
stretched: '#2a7fb8',
|
|
24
|
+
outline: '#00000000',
|
|
25
|
+
outlineWidth: 0,
|
|
26
|
+
},
|
|
27
|
+
props: { stroke: '#111111', fill: '#f0f0f0', strokeWidth: 0.008 },
|
|
28
|
+
annotation: {
|
|
29
|
+
stroke: '#c1121f',
|
|
30
|
+
strokeWidth: 0.005,
|
|
31
|
+
accent: '#c1121f',
|
|
32
|
+
color: '#c1121f',
|
|
33
|
+
fontFamily: SANS,
|
|
34
|
+
fontSize: 0.045,
|
|
35
|
+
dash: '0.03 0.02',
|
|
36
|
+
},
|
|
37
|
+
text: { color: '#111111', muted: '#666666', fontFamily: SANS, titleSize: 0.075, captionSize: 0.042 },
|
|
38
|
+
};
|
|
39
|
+
const anatomy = {
|
|
40
|
+
...stick,
|
|
41
|
+
id: 'anatomy',
|
|
42
|
+
label: 'Anatomical infographic',
|
|
43
|
+
figure: { ...stick.figure, stroke: '#3d3d3d', strokeWidth: 0.012, joints: 'dots', jointRadius: 0.009 },
|
|
44
|
+
head: { ...stick.head, fill: '#f5efe8', stroke: '#3d3d3d', strokeWidth: 0.012 },
|
|
45
|
+
muscles: {
|
|
46
|
+
show: true,
|
|
47
|
+
base: '#e0cfc2',
|
|
48
|
+
opacity: 0.95,
|
|
49
|
+
engaged: '#d1495b',
|
|
50
|
+
stretched: '#3d7ea6',
|
|
51
|
+
outline: '#9c8574',
|
|
52
|
+
outlineWidth: 0.003,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
const silhouette = {
|
|
56
|
+
...stick,
|
|
57
|
+
id: 'silhouette',
|
|
58
|
+
label: 'Filled silhouette',
|
|
59
|
+
figure: {
|
|
60
|
+
...stick.figure,
|
|
61
|
+
stroke: '#111111',
|
|
62
|
+
strokeWidth: 0.062,
|
|
63
|
+
joints: 'none',
|
|
64
|
+
jointRadius: 0,
|
|
65
|
+
torsoWidth: 0.075,
|
|
66
|
+
fill: '#111111',
|
|
67
|
+
},
|
|
68
|
+
head: { shape: 'ellipse', rx: 0.05, ry: 0.066, fill: '#111111', stroke: '#111111', strokeWidth: 0.01 },
|
|
69
|
+
};
|
|
70
|
+
const blueprint = {
|
|
71
|
+
...stick,
|
|
72
|
+
id: 'blueprint',
|
|
73
|
+
label: 'Blueprint',
|
|
74
|
+
background: '#f3f7fb',
|
|
75
|
+
figure: { ...stick.figure, stroke: '#1b3a5c', strokeWidth: 0.012, jointRadius: 0.01 },
|
|
76
|
+
head: { shape: 'circle', rx: 0.05, ry: 0.05, fill: 'none', stroke: '#1b3a5c', strokeWidth: 0.012 },
|
|
77
|
+
props: { stroke: '#1b3a5c', fill: '#e2ecf5', strokeWidth: 0.006 },
|
|
78
|
+
annotation: { ...stick.annotation, stroke: '#c1121f', accent: '#c1121f', color: '#1b3a5c', strokeWidth: 0.004 },
|
|
79
|
+
text: { ...stick.text, color: '#1b3a5c', muted: '#5c7998' },
|
|
80
|
+
};
|
|
81
|
+
const ink = {
|
|
82
|
+
...stick,
|
|
83
|
+
id: 'ink',
|
|
84
|
+
label: 'Brush ink',
|
|
85
|
+
figure: { ...stick.figure, strokeWidth: 0.038, joints: 'none', jointRadius: 0, torsoWidth: 0.03 },
|
|
86
|
+
head: { ...stick.head, rx: 0.05, ry: 0.064, strokeWidth: 0.032 },
|
|
87
|
+
};
|
|
88
|
+
const poster = {
|
|
89
|
+
...stick,
|
|
90
|
+
id: 'poster',
|
|
91
|
+
label: 'Poster',
|
|
92
|
+
background: '#fdf6ec',
|
|
93
|
+
figure: { ...stick.figure, stroke: '#1d1d1b', strokeWidth: 0.03, torsoWidth: 0.05, jointRadius: 0.016 },
|
|
94
|
+
head: { ...stick.head, fill: '#f4a259', stroke: '#1d1d1b', strokeWidth: 0.026, rx: 0.05, ry: 0.066 },
|
|
95
|
+
props: { stroke: '#1d1d1b', fill: '#8cb369', strokeWidth: 0.012 },
|
|
96
|
+
annotation: { ...stick.annotation, stroke: '#bc4b51', accent: '#bc4b51', color: '#1d1d1b' },
|
|
97
|
+
};
|
|
98
|
+
const minimal = {
|
|
99
|
+
...stick,
|
|
100
|
+
id: 'minimal',
|
|
101
|
+
label: 'Minimal',
|
|
102
|
+
figure: { ...stick.figure, stroke: '#9aa0a6', strokeWidth: 0.01, joints: 'none', jointRadius: 0 },
|
|
103
|
+
head: { ...stick.head, stroke: '#9aa0a6', strokeWidth: 0.01 },
|
|
104
|
+
annotation: { ...stick.annotation, stroke: '#9aa0a6', color: '#9aa0a6', accent: '#9aa0a6' },
|
|
105
|
+
};
|
|
106
|
+
export const STYLES = { stick, anatomy, silhouette, blueprint, ink, poster, minimal };
|
|
107
|
+
export const STYLE_IDS = Object.keys(STYLES);
|
|
108
|
+
export const isStyleId = (value) => value in STYLES;
|
|
109
|
+
/** Merge a partial override one level deep - deep enough for the token tree, shallow enough to stay predictable. */
|
|
110
|
+
export const resolveStyle = (id = 'stick', override = {}) => {
|
|
111
|
+
const base = STYLES[id];
|
|
112
|
+
const merged = { ...base };
|
|
113
|
+
for (const [key, value] of Object.entries(override)) {
|
|
114
|
+
const current = merged[key];
|
|
115
|
+
merged[key] =
|
|
116
|
+
typeof value === 'object' && value !== null && typeof current === 'object' && current !== null
|
|
117
|
+
? { ...current, ...value }
|
|
118
|
+
: value;
|
|
119
|
+
}
|
|
120
|
+
return merged;
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/render/styles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type AttrValue = string | number | undefined;
|
|
2
|
+
export interface SvgNode {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly attrs: Readonly<Record<string, AttrValue>>;
|
|
5
|
+
readonly children: readonly SvgNode[];
|
|
6
|
+
readonly text?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Round coordinates so the same pose always serialises to the same bytes. */
|
|
9
|
+
export declare const num: (value: number) => number;
|
|
10
|
+
export declare const el: (name: string, attrs?: Record<string, AttrValue>, children?: readonly SvgNode[]) => SvgNode;
|
|
11
|
+
export declare const textEl: (name: string, attrs: Record<string, AttrValue>, text: string) => SvgNode;
|
|
12
|
+
export declare const group: (attrs: Record<string, AttrValue>, children: readonly SvgNode[]) => SvgNode;
|
|
13
|
+
/**
|
|
14
|
+
* Serialise to a standalone SVG document. xmlbuilder2 entity-escapes text and
|
|
15
|
+
* attributes, so the output is safe to inline into HTML - a pose name can never
|
|
16
|
+
* break out of a <text> element.
|
|
17
|
+
*/
|
|
18
|
+
export declare const serialize: (root: SvgNode) => string;
|
|
19
|
+
//# sourceMappingURL=svg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../src/render/svg.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAEpD,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,8EAA8E;AAC9E,eAAO,MAAM,GAAG,GAAI,OAAO,MAAM,KAAG,MAGnC,CAAC;AAEF,eAAO,MAAM,EAAE,GAAI,MAAM,MAAM,EAAE,QAAO,MAAM,CAAC,MAAM,EAAE,SAAS,CAAM,EAAE,WAAU,SAAS,OAAO,EAAO,KAAG,OAI1G,CAAC;AAEH,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,MAAM,KAAG,OAKpF,CAAC;AAEH,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,SAAS,OAAO,EAAE,KAAG,OAC7C,CAAC;AAa3C;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,OAAO,KAAG,MAIzC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { create } from 'xmlbuilder2';
|
|
2
|
+
const DECIMALS = 3;
|
|
3
|
+
/** Round coordinates so the same pose always serialises to the same bytes. */
|
|
4
|
+
export const num = (value) => {
|
|
5
|
+
const rounded = Number(value.toFixed(DECIMALS));
|
|
6
|
+
return Object.is(rounded, -0) ? 0 : rounded;
|
|
7
|
+
};
|
|
8
|
+
export const el = (name, attrs = {}, children = []) => ({
|
|
9
|
+
name,
|
|
10
|
+
attrs,
|
|
11
|
+
children,
|
|
12
|
+
});
|
|
13
|
+
export const textEl = (name, attrs, text) => ({
|
|
14
|
+
name,
|
|
15
|
+
attrs,
|
|
16
|
+
children: [],
|
|
17
|
+
text,
|
|
18
|
+
});
|
|
19
|
+
export const group = (attrs, children) => el('g', attrs, children.filter(Boolean));
|
|
20
|
+
const build = (node, parent) => {
|
|
21
|
+
const attrs = Object.fromEntries(Object.entries(node.attrs)
|
|
22
|
+
.filter(([, v]) => v !== undefined)
|
|
23
|
+
.map(([k, v]) => [k, typeof v === 'number' ? String(num(v)) : String(v)]));
|
|
24
|
+
const child = parent.ele(node.name, attrs);
|
|
25
|
+
if (node.text !== undefined)
|
|
26
|
+
child.txt(node.text);
|
|
27
|
+
for (const c of node.children)
|
|
28
|
+
build(c, child);
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Serialise to a standalone SVG document. xmlbuilder2 entity-escapes text and
|
|
32
|
+
* attributes, so the output is safe to inline into HTML - a pose name can never
|
|
33
|
+
* break out of a <text> element.
|
|
34
|
+
*/
|
|
35
|
+
export const serialize = (root) => {
|
|
36
|
+
const doc = create();
|
|
37
|
+
build(root, doc);
|
|
38
|
+
return doc.end({ prettyPrint: true, headless: true, indent: ' ' });
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=svg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg.js","sourceRoot":"","sources":["../../src/render/svg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAWrC,MAAM,QAAQ,GAAG,CAAC,CAAC;AAEnB,8EAA8E;AAC9E,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,KAAa,EAAU,EAAE;IAC3C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,QAAmC,EAAE,EAAE,WAA+B,EAAE,EAAW,EAAE,CAAC,CAAC;IACtH,IAAI;IACJ,KAAK;IACL,QAAQ;CACT,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,KAAgC,EAAE,IAAY,EAAW,EAAE,CAAC,CAAC;IAChG,IAAI;IACJ,KAAK;IACL,QAAQ,EAAE,EAAE;IACZ,IAAI;CACL,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAgC,EAAE,QAA4B,EAAW,EAAE,CAC/F,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAE3C,MAAM,KAAK,GAAG,CAAC,IAAa,EAAE,MAAoE,EAAQ,EAAE;IAC1G,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAC9B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;SACvB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC;SAClC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAC5E,CAAC;IACF,MAAM,KAAK,GAAI,MAAoC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC1E,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;QAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ;QAAE,KAAK,CAAC,CAAC,EAAE,KAAc,CAAC,CAAC;AAC1D,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAa,EAAU,EAAE;IACjD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACjB,OAAO,GAAG,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export a solved skeleton as keypoints in the two standard layouts, so asanakit
|
|
3
|
+
* output can feed anything that already speaks pose-estimation data.
|
|
4
|
+
*
|
|
5
|
+
* The landmark NAMES and EDGE lists below restate the public layouts of
|
|
6
|
+
* MediaPipe BlazePose (33) and COCO (17), as published in the Apache-2.0
|
|
7
|
+
* licensed tfjs-models / mediapipe projects. Only the layout is reused; the
|
|
8
|
+
* geometry is asanakit's own.
|
|
9
|
+
*/
|
|
10
|
+
import type { Skeleton } from '../core/types.js';
|
|
11
|
+
export declare const MEDIAPIPE_33: readonly ["nose", "left_eye_inner", "left_eye", "left_eye_outer", "right_eye_inner", "right_eye", "right_eye_outer", "left_ear", "right_ear", "mouth_left", "mouth_right", "left_shoulder", "right_shoulder", "left_elbow", "right_elbow", "left_wrist", "right_wrist", "left_pinky", "right_pinky", "left_index", "right_index", "left_thumb", "right_thumb", "left_hip", "right_hip", "left_knee", "right_knee", "left_ankle", "right_ankle", "left_heel", "right_heel", "left_foot_index", "right_foot_index"];
|
|
12
|
+
export declare const COCO_17: readonly ["nose", "left_eye", "right_eye", "left_ear", "right_ear", "left_shoulder", "right_shoulder", "left_elbow", "right_elbow", "left_wrist", "right_wrist", "left_hip", "right_hip", "left_knee", "right_knee", "left_ankle", "right_ankle"];
|
|
13
|
+
export type KeypointFormat = 'mediapipe33' | 'coco17';
|
|
14
|
+
export interface Keypoint {
|
|
15
|
+
readonly index: number;
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly x: number;
|
|
18
|
+
readonly y: number;
|
|
19
|
+
}
|
|
20
|
+
export interface KeypointSet {
|
|
21
|
+
readonly format: KeypointFormat;
|
|
22
|
+
readonly space: 'stature' | 'normalized';
|
|
23
|
+
readonly keypoints: readonly Keypoint[];
|
|
24
|
+
readonly edges: readonly (readonly [number, number])[];
|
|
25
|
+
}
|
|
26
|
+
export interface KeypointOptions {
|
|
27
|
+
/** Emit image coordinates: 0..1 across the pose bounds, y pointing down. */
|
|
28
|
+
readonly normalize?: boolean;
|
|
29
|
+
}
|
|
30
|
+
export declare const toKeypoints: (skeleton: Skeleton, format: KeypointFormat, options?: KeypointOptions) => KeypointSet;
|
|
31
|
+
//# sourceMappingURL=keypoints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keypoints.d.ts","sourceRoot":"","sources":["../../src/standards/keypoints.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGjD,eAAO,MAAM,YAAY,mfAOf,CAAC;AAEX,eAAO,MAAM,OAAO,mPAIV,CAAC;AAeX,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,QAAQ,CAAC;AAEtD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,YAAY,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AA0ED,eAAO,MAAM,WAAW,GACtB,UAAU,QAAQ,EAClB,QAAQ,cAAc,EACtB,UAAS,eAAoB,KAC5B,WA2BF,CAAC"}
|