@kvmet/beefwife 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/DESCRIPTOR.md +221 -0
- package/LICENSE +373 -0
- package/README.md +258 -2
- package/beefwife.example.json +260 -0
- package/beefwife.js +3182 -0
- package/beefwife.min.js +4 -0
- package/package.json +73 -4
- package/samples/bounding.json +260 -0
- package/samples/chevron-guy.json +270 -0
- package/samples/long-girl.json +233 -0
- package/samples/peristaltic.json +260 -0
- package/samples/reticulating.json +260 -0
- package/samples/slow-guy.json +233 -0
- package/samples/undulating.json +260 -0
- package/src/atlas.mjs +285 -0
- package/src/beefwife.mjs +540 -0
- package/src/bend.mjs +172 -0
- package/src/body.mjs +501 -0
- package/src/carry.mjs +60 -0
- package/src/chain.mjs +83 -0
- package/src/descriptor.mjs +426 -0
- package/src/display.mjs +65 -0
- package/src/drive.mjs +77 -0
- package/src/geometry.mjs +240 -0
- package/src/global.mjs +14 -0
- package/src/graphics.mjs +715 -0
- package/src/legs.mjs +223 -0
- package/src/limits.mjs +19 -0
- package/src/model.mjs +267 -0
- package/src/pixi.mjs +11 -0
- package/src/schema.mjs +243 -0
- package/src/skin.mjs +313 -0
- package/src/tables.mjs +109 -0
package/README.md
CHANGED
|
@@ -1,3 +1,259 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Beefwife
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Beefwife simulates and draws one procedurally animated chain-body creature, a
|
|
4
|
+
beefwife, as a Pixi display object. A descriptor, plain JSON, defines its body,
|
|
5
|
+
gait, and look.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import { Beefwife, Descriptor } from "@kvmet/beefwife";
|
|
9
|
+
|
|
10
|
+
const response = await fetch("slow-guy.json");
|
|
11
|
+
const descriptor = Descriptor.read(await response.json());
|
|
12
|
+
const beefwife = new Beefwife(descriptor, { position: { x: 200, y: 150 } });
|
|
13
|
+
app.stage.addChild(beefwife);
|
|
14
|
+
|
|
15
|
+
app.ticker.add((ticker) => {
|
|
16
|
+
const dt = Math.min(ticker.deltaMS / 1000, 1 / 30);
|
|
17
|
+
beefwife.step(dt, { direction: { x: 1, y: 0.2 } });
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Beefwife has no clock, routing, or page placement. You step it and you steer
|
|
22
|
+
it. To put creatures on a web page with none of that work, use
|
|
23
|
+
[`@kvmet/beefwife-canvas`](https://www.npmjs.com/package/@kvmet/beefwife-canvas).
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm install @kvmet/beefwife pixi.js
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or load the classic script after Pixi:
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<script src="https://cdn.jsdelivr.net/npm/pixi.js@8.23.0/dist/pixi.min.js"></script>
|
|
35
|
+
<script src="https://cdn.jsdelivr.net/npm/@kvmet/beefwife@0.1.1/beefwife.min.js"></script>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| Entry | Use |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `import` | `src/beefwife.mjs`. Exports `Beefwife` and `Descriptor`, and imports `pixi.js`, so a bundler gives the page and the library one copy. |
|
|
41
|
+
| `require`, `beefwife.min.js` | Classic script. Reads `window.PIXI` and adds one global, `Beefwife`, with the descriptor API at `Beefwife.Descriptor`. |
|
|
42
|
+
| `beefwife.js` | The classic script, unminified. |
|
|
43
|
+
|
|
44
|
+
Pixi 8.21.0 or newer is required. In earlier 8.x releases, destroying one
|
|
45
|
+
WebGPU renderer can break another. WebGL and WebGPU are both supported.
|
|
46
|
+
|
|
47
|
+
Without `window.PIXI`, the classic script still simulates. It creates no
|
|
48
|
+
display objects, so a server or a test gets poses without a renderer.
|
|
49
|
+
|
|
50
|
+
In Node, `require` and `import` load separate copies with separate `Beefwife`
|
|
51
|
+
classes, and `instanceof` fails between them. Use one form in a program.
|
|
52
|
+
|
|
53
|
+
### Samples
|
|
54
|
+
|
|
55
|
+
Seven descriptors ship under `samples/`: `bounding`, `chevron-guy`,
|
|
56
|
+
`long-girl`, `peristaltic`, `reticulating`, `slow-guy`, and `undulating`.
|
|
57
|
+
`beefwife.example.json` uses every field. A CDN serves them without an install:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
https://cdn.jsdelivr.net/npm/@kvmet/beefwife@0.1.1/samples/slow-guy.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API
|
|
64
|
+
|
|
65
|
+
All coordinates are world pixels and all angles are radians. Invalid input
|
|
66
|
+
throws and changes nothing; no value is clamped.
|
|
67
|
+
|
|
68
|
+
### `new Beefwife(descriptor, options = {})`
|
|
69
|
+
|
|
70
|
+
Builds a creature from a descriptor. With Pixi present, this also rejects SVG
|
|
71
|
+
paths and colours that Pixi cannot parse, and shapes too large to draw.
|
|
72
|
+
|
|
73
|
+
| Option | Default | Meaning |
|
|
74
|
+
| --- | --- | --- |
|
|
75
|
+
| `position` | `{ x: 0, y: 0 }` | Where the head starts. |
|
|
76
|
+
| `direction` | `{ x: 1, y: 0 }` | Which way the head points. Any nonzero vector; it is normalized. |
|
|
77
|
+
| `phase` | `0` | Starting gait phase. |
|
|
78
|
+
| `random` | `Math.random` | A function returning numbers from 0 up to 1. The only source of variation, in leg proportions, step timing, and breathing. |
|
|
79
|
+
| `render` | See below | How the creature draws. |
|
|
80
|
+
|
|
81
|
+
`render` is kept, not copied, so a host can change its fields while the
|
|
82
|
+
creature runs.
|
|
83
|
+
|
|
84
|
+
| `render` field | Default | Meaning |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| `roundVertices` | `false` | Snap vertices to the output pixel grid. |
|
|
87
|
+
| `pixelResolution` | `1` | Output pixels per world pixel, `1e-6` to `1e6`. Set it from the renderer resolution and update it when that changes. |
|
|
88
|
+
| `kneeProjection` | `null` | `{ centerX, centerY, perspective, maxOffset }`. Pushes each drawn knee away from the center by distance times knee height times `perspective`, up to `maxOffset` (default 256). Changes only the drawn knees. |
|
|
89
|
+
|
|
90
|
+
A `pixelResolution` that is changed to an invalid value is reported once,
|
|
91
|
+
after the render pass, and drawing continues at the last valid value.
|
|
92
|
+
|
|
93
|
+
### `step(dt, controls = {})`
|
|
94
|
+
|
|
95
|
+
Simulates `dt` seconds in fixed steps of 1/60 s. `dt` is never capped: one
|
|
96
|
+
second costs sixty steps. Cap it yourself, usually at one frame, so a tab that
|
|
97
|
+
resumes after a minute does not simulate the whole minute.
|
|
98
|
+
|
|
99
|
+
| Control | Default | Meaning |
|
|
100
|
+
| --- | --- | --- |
|
|
101
|
+
| `direction` | The last one given | The way the creature turns toward. |
|
|
102
|
+
| `throttle` | `1` | From 0 to 1. Scales gait speed, gait strength, and steering. At 0 the creature coasts to a stop. |
|
|
103
|
+
|
|
104
|
+
### `setDescriptor(descriptor)`
|
|
105
|
+
|
|
106
|
+
Changes the creature to a new descriptor and keeps as much of it as the new
|
|
107
|
+
descriptor allows. See [Edits keep the creature](#edits-keep-the-creature).
|
|
108
|
+
|
|
109
|
+
### `reset(options = {})`
|
|
110
|
+
|
|
111
|
+
Places the creature again with no motion. Takes `position`, `direction`, and
|
|
112
|
+
`phase`, which default to the current head, head direction, and gait phase. A
|
|
113
|
+
given `direction` also becomes the direction `step` uses when its control is
|
|
114
|
+
omitted.
|
|
115
|
+
|
|
116
|
+
### `translate({ x, y })`
|
|
117
|
+
|
|
118
|
+
Moves the whole creature and keeps its motion, gait, and steering. Use it to
|
|
119
|
+
wrap a creature around a world edge.
|
|
120
|
+
|
|
121
|
+
### `getPose()`
|
|
122
|
+
|
|
123
|
+
Returns `{ head, center, direction }`, each `{ x, y }`. `center` is the mean of
|
|
124
|
+
all chain points; `direction` is the unit vector the head points along. The
|
|
125
|
+
same object is refreshed after each change, so you can keep the reference.
|
|
126
|
+
Treat it as read-only.
|
|
127
|
+
|
|
128
|
+
### `restLength`
|
|
129
|
+
|
|
130
|
+
The chain's length at rest. `center` can trail the head by up to this
|
|
131
|
+
distance, so add it to the margin when you test whether a creature is in view.
|
|
132
|
+
|
|
133
|
+
### `descriptor`
|
|
134
|
+
|
|
135
|
+
The descriptor the creature is built from.
|
|
136
|
+
|
|
137
|
+
### `getBendResponse(into = [])`
|
|
138
|
+
|
|
139
|
+
Returns one `{ joint, commanded, delivered }` per inner chain joint: the bend
|
|
140
|
+
the gait asks for and the bend the body makes, positive to the left. Use it to
|
|
141
|
+
see what a `gait.bend` amplitude produces on a given body. Pass an array to
|
|
142
|
+
fill it instead of allocating a new one.
|
|
143
|
+
|
|
144
|
+
### `destroy()`
|
|
145
|
+
|
|
146
|
+
Frees every display object the creature owns and removes it from its parent.
|
|
147
|
+
Call it for each creature you drop; nothing else frees them. Afterwards `step`,
|
|
148
|
+
`setDescriptor`, `reset`, `translate`, and `getBendResponse` throw.
|
|
149
|
+
`descriptor` and the last pose stay readable.
|
|
150
|
+
|
|
151
|
+
### `error` event
|
|
152
|
+
|
|
153
|
+
A texture that fails to render is emitted as `error` on the creature. With no
|
|
154
|
+
listener, the error is thrown. The texture is tried again only after an edit,
|
|
155
|
+
a resolution change, or a renderer change.
|
|
156
|
+
|
|
157
|
+
### `Beefwife.MAX_WORLD_COORDINATE`
|
|
158
|
+
|
|
159
|
+
`1e9`. Positions, translations, and projection centers must be within this
|
|
160
|
+
distance of the origin on each axis. A creature that walks to the limit is
|
|
161
|
+
moved back inside it, motion included.
|
|
162
|
+
|
|
163
|
+
## Descriptor
|
|
164
|
+
|
|
165
|
+
`Descriptor` reads, checks, resizes, and writes descriptors. Every function
|
|
166
|
+
throws an `Error` whose message starts with the path of the bad field, such as
|
|
167
|
+
`$.legs.pairs: must be an integer`. The format is in
|
|
168
|
+
[DESCRIPTOR.md](https://github.com/kvmet/beefwife/blob/main/beefwife/DESCRIPTOR.md).
|
|
169
|
+
|
|
170
|
+
| Member | Does |
|
|
171
|
+
| --- | --- |
|
|
172
|
+
| `parse(text)` | Parses JSON text and checks it. Returns a new descriptor. |
|
|
173
|
+
| `read(value)` | Checks a parsed value. Returns a new plain copy with keys in canonical order. |
|
|
174
|
+
| `stringify(value, space = 2)` | Checks a descriptor and returns canonical JSON text. |
|
|
175
|
+
| `scale(descriptor, factor)` | Returns a copy resized by `factor`, with the same timing and feel. A field the result pushes out of range is an error. |
|
|
176
|
+
| `bounds(path)` | What the schema allows for one field. |
|
|
177
|
+
| `VERSION` | `1`, the schema version this release reads. |
|
|
178
|
+
| `LIMITS` | Size limits: `chunks`, `definitions`, `placements`, `instances`, `name`, `path`, and `pathTotal`. |
|
|
179
|
+
| `ID_PATTERN` | Pattern for definition ids. |
|
|
180
|
+
| `NAME_PATTERN` | Pattern for `name`. |
|
|
181
|
+
|
|
182
|
+
`bounds` names a field with dots, an array item with `[]`, and a record entry
|
|
183
|
+
with `*`. It lets an editor take a range from the schema instead of keeping a
|
|
184
|
+
second copy:
|
|
185
|
+
|
|
186
|
+
```js
|
|
187
|
+
Descriptor.bounds("legs.pairs");
|
|
188
|
+
// { kind: "number", min: 0, max: 128, integer: true, nullable: false }
|
|
189
|
+
Descriptor.bounds("chain.skin.ornaments[].side");
|
|
190
|
+
// { kind: "choice", values: ["left", "right", "both"], nullable: false }
|
|
191
|
+
Descriptor.bounds("definitions.paints.*.stroke.width");
|
|
192
|
+
// { kind: "number", min: 0, max: 1000, integer: false, nullable: false }
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Every result has `kind` and `nullable`. Numbers add `min`, `max`, and
|
|
196
|
+
`integer`. Strings add `minLength`, `maxLength`, `pattern`, and `blankAllowed`.
|
|
197
|
+
Choices add `values`, objects add `fields`, arrays add `maxLength`, and records
|
|
198
|
+
add `minEntries`, `maxEntries`, and `keyPattern`. A few rules join several
|
|
199
|
+
fields and cannot show in one field's bounds; DESCRIPTOR.md lists them.
|
|
200
|
+
|
|
201
|
+
## Descriptors are values
|
|
202
|
+
|
|
203
|
+
A creature freezes the descriptor object it is given, and every creature given
|
|
204
|
+
the same object shares one compiled model. A cast of a thousand compiles once.
|
|
205
|
+
To change a descriptor, make a copy, change the copy, and pass it to
|
|
206
|
+
`setDescriptor`.
|
|
207
|
+
|
|
208
|
+
## Edits keep the creature
|
|
209
|
+
|
|
210
|
+
`setDescriptor` checks the new descriptor first. If it fails, the creature is
|
|
211
|
+
unchanged. A failed call may still have drawn from `random`.
|
|
212
|
+
|
|
213
|
+
A successful edit keeps position, motion, steering, and gait and breathing
|
|
214
|
+
phase. When a section gains or loses chunks, the chunks that remain keep their
|
|
215
|
+
place and motion, and new chunks start between their neighbours. Feet rebuild
|
|
216
|
+
only when the number of leg pairs changes, and ornament motion rebuilds only
|
|
217
|
+
when the list of ornaments changes. A change in breathing strength eases in
|
|
218
|
+
over at most 0.2 s.
|
|
219
|
+
|
|
220
|
+
Display objects are kept the same way. Only the ones the edit changes are
|
|
221
|
+
rebuilt, and old shapes keep moving with the body until their replacements are
|
|
222
|
+
ready.
|
|
223
|
+
|
|
224
|
+
## Rendering
|
|
225
|
+
|
|
226
|
+
`Beefwife` extends `PIXI.Container`. Add it to a stage and render the stage;
|
|
227
|
+
the creature updates its display objects in Pixi's render pass. Its own parts
|
|
228
|
+
sit in one child container, so children you add to it keep the order you give
|
|
229
|
+
them. The library owns two inherited properties: `label` holds the
|
|
230
|
+
descriptor's `name`, and `onRender` draws the creature. Put your own label or
|
|
231
|
+
render callback on a parent.
|
|
232
|
+
|
|
233
|
+
Drawing order, back to front:
|
|
234
|
+
|
|
235
|
+
1. Feet, then legs.
|
|
236
|
+
2. `under` ornaments, in descriptor order.
|
|
237
|
+
3. The ribbon, then plates from tail to head.
|
|
238
|
+
4. `over` ornaments, in descriptor order.
|
|
239
|
+
|
|
240
|
+
Feet, plates, and ornaments are drawn from one texture sheet per look and
|
|
241
|
+
renderer. The sheet is at most 2048 × 2048 texels and each shape at most
|
|
242
|
+
1024 × 1024. When a creature's shapes do not fit, all of them draw at lower
|
|
243
|
+
detail; size and position do not change.
|
|
244
|
+
|
|
245
|
+
## Development
|
|
246
|
+
|
|
247
|
+
`beefwife.js` and `beefwife.min.js` are generated from `src/` by `npm run
|
|
248
|
+
build`; do not edit them directly. From the repository root:
|
|
249
|
+
|
|
250
|
+
```sh
|
|
251
|
+
bb descriptor # schema
|
|
252
|
+
bb beefwife-model # descriptor compilation
|
|
253
|
+
bb beefwife-api # public API
|
|
254
|
+
bb beefwife-package # build, then check the packed package
|
|
255
|
+
bb test # every headless suite
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Beefwife is released under the
|
|
259
|
+
[Mozilla Public License 2.0](https://github.com/kvmet/beefwife/blob/main/beefwife/LICENSE).
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "beefwife",
|
|
4
|
+
"definitions": {
|
|
5
|
+
"materials": {
|
|
6
|
+
"body": {
|
|
7
|
+
"velocityRetention": 0.06928872574536875,
|
|
8
|
+
"jointCorrection": 0.5,
|
|
9
|
+
"linkCorrection": 0.6,
|
|
10
|
+
"grip": {
|
|
11
|
+
"forward": 0.05,
|
|
12
|
+
"backward": 0.62,
|
|
13
|
+
"lateral": 0.91
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"shapes": {
|
|
18
|
+
"bodyPlate": {
|
|
19
|
+
"path": "M -4 -4 L 0 -5.5 L 4.5 -4 L 6 0 L 4.5 4 L 0 5 L -4 3.5 L -5.5 0 Z"
|
|
20
|
+
},
|
|
21
|
+
"eye": {
|
|
22
|
+
"path": "M -2 -2 L 0 -3 L 2.5 -2 L 2.5 0.5 L 0 1.5 L -2.5 0 Z"
|
|
23
|
+
},
|
|
24
|
+
"foot": {
|
|
25
|
+
"path": "M -1.2 -0.65 L 0.65 -0.9 L 1.2 -0.35 L 1.2 0.35 L 0.65 0.9 L -1.2 0.65 Z"
|
|
26
|
+
},
|
|
27
|
+
"headPlate": {
|
|
28
|
+
"path": "M -5.5 -2 L 2 -2 L 3.5 -1 L 3.5 1 L 2 2 L -5.5 2 Z"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"paints": {
|
|
32
|
+
"eye": {
|
|
33
|
+
"fill": "#050505",
|
|
34
|
+
"stroke": {
|
|
35
|
+
"colour": "#ffffff",
|
|
36
|
+
"width": 3.1
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"foot": {
|
|
40
|
+
"fill": "#5b6b7a",
|
|
41
|
+
"stroke": {
|
|
42
|
+
"colour": "#ff0000",
|
|
43
|
+
"width": 3.1
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"leg": {
|
|
47
|
+
"fill": "#39424e",
|
|
48
|
+
"stroke": null
|
|
49
|
+
},
|
|
50
|
+
"ribbon": {
|
|
51
|
+
"fill": "#7a1414",
|
|
52
|
+
"stroke": null
|
|
53
|
+
},
|
|
54
|
+
"shell": {
|
|
55
|
+
"fill": "#ff0000",
|
|
56
|
+
"stroke": {
|
|
57
|
+
"colour": "#ff0000",
|
|
58
|
+
"width": 3.1
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"gait": {
|
|
64
|
+
"cyclesPerSecond": 1.35,
|
|
65
|
+
"phaseLagRadiansPerPixel": 0.0391666666667,
|
|
66
|
+
"bend": {
|
|
67
|
+
"amplitude": 0.84,
|
|
68
|
+
"harmonic": 1
|
|
69
|
+
},
|
|
70
|
+
"thrust": {
|
|
71
|
+
"acceleration": 0,
|
|
72
|
+
"harmonic": 1,
|
|
73
|
+
"phaseOffset": 0.36,
|
|
74
|
+
"dutyCycle": 0.5
|
|
75
|
+
},
|
|
76
|
+
"gather": {
|
|
77
|
+
"amplitude": 0.12,
|
|
78
|
+
"harmonic": 2,
|
|
79
|
+
"phaseOffset": 0
|
|
80
|
+
},
|
|
81
|
+
"contact": {
|
|
82
|
+
"amplitude": 0.97,
|
|
83
|
+
"harmonic": 1,
|
|
84
|
+
"phaseOffset": -0.25,
|
|
85
|
+
"dutyCycle": 0.5
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"chain": {
|
|
89
|
+
"physics": {
|
|
90
|
+
"autoLift": {
|
|
91
|
+
"amount": 0.59,
|
|
92
|
+
"share": 0.4,
|
|
93
|
+
"rate": 12
|
|
94
|
+
},
|
|
95
|
+
"steering": {
|
|
96
|
+
"gain": 0.6,
|
|
97
|
+
"limit": 0.5,
|
|
98
|
+
"rate": 6
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"breathing": 0,
|
|
102
|
+
"sections": {
|
|
103
|
+
"head": {
|
|
104
|
+
"chunks": 2,
|
|
105
|
+
"spacing": 12,
|
|
106
|
+
"material": "body",
|
|
107
|
+
"motionScale": {
|
|
108
|
+
"bend": 0,
|
|
109
|
+
"thrust": 1,
|
|
110
|
+
"gather": 1,
|
|
111
|
+
"contact": 1
|
|
112
|
+
},
|
|
113
|
+
"profile": {
|
|
114
|
+
"ribbonWidth": {
|
|
115
|
+
"start": 2.5,
|
|
116
|
+
"end": 4.5
|
|
117
|
+
},
|
|
118
|
+
"plateScale": {
|
|
119
|
+
"start": 1,
|
|
120
|
+
"end": 1
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"trunk": {
|
|
125
|
+
"chunks": 16,
|
|
126
|
+
"spacing": 12,
|
|
127
|
+
"material": "body",
|
|
128
|
+
"motionScale": {
|
|
129
|
+
"bend": 1,
|
|
130
|
+
"thrust": 1,
|
|
131
|
+
"gather": 1,
|
|
132
|
+
"contact": 1
|
|
133
|
+
},
|
|
134
|
+
"profile": {
|
|
135
|
+
"ribbonWidth": {
|
|
136
|
+
"start": 4.5,
|
|
137
|
+
"end": 4.5
|
|
138
|
+
},
|
|
139
|
+
"plateScale": {
|
|
140
|
+
"start": 1,
|
|
141
|
+
"end": 1
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"tail": {
|
|
146
|
+
"chunks": 9,
|
|
147
|
+
"spacing": 12,
|
|
148
|
+
"material": "body",
|
|
149
|
+
"motionScale": {
|
|
150
|
+
"bend": 1,
|
|
151
|
+
"thrust": 1,
|
|
152
|
+
"gather": 1,
|
|
153
|
+
"contact": 1
|
|
154
|
+
},
|
|
155
|
+
"profile": {
|
|
156
|
+
"ribbonWidth": {
|
|
157
|
+
"start": 4.5,
|
|
158
|
+
"end": 0
|
|
159
|
+
},
|
|
160
|
+
"plateScale": {
|
|
161
|
+
"start": 1,
|
|
162
|
+
"end": 0.55
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
"skin": {
|
|
168
|
+
"loadScale": 0.35,
|
|
169
|
+
"ribbon": {
|
|
170
|
+
"paint": "ribbon"
|
|
171
|
+
},
|
|
172
|
+
"plates": [
|
|
173
|
+
{
|
|
174
|
+
"id": "head-shell",
|
|
175
|
+
"shape": "headPlate",
|
|
176
|
+
"paint": "shell",
|
|
177
|
+
"at": {
|
|
178
|
+
"section": "head",
|
|
179
|
+
"from": "head",
|
|
180
|
+
"offset": 0
|
|
181
|
+
},
|
|
182
|
+
"repeat": {
|
|
183
|
+
"count": 1,
|
|
184
|
+
"step": 1
|
|
185
|
+
},
|
|
186
|
+
"scale": 1
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"id": "body-shell",
|
|
190
|
+
"shape": "bodyPlate",
|
|
191
|
+
"paint": "shell",
|
|
192
|
+
"at": {
|
|
193
|
+
"section": null,
|
|
194
|
+
"from": "head",
|
|
195
|
+
"offset": 1
|
|
196
|
+
},
|
|
197
|
+
"repeat": {
|
|
198
|
+
"count": null,
|
|
199
|
+
"step": 1
|
|
200
|
+
},
|
|
201
|
+
"scale": 1
|
|
202
|
+
}
|
|
203
|
+
],
|
|
204
|
+
"ornaments": [
|
|
205
|
+
{
|
|
206
|
+
"id": "eyes",
|
|
207
|
+
"shape": "eye",
|
|
208
|
+
"paint": "eye",
|
|
209
|
+
"at": {
|
|
210
|
+
"section": "head",
|
|
211
|
+
"from": "head",
|
|
212
|
+
"offset": 1
|
|
213
|
+
},
|
|
214
|
+
"repeat": {
|
|
215
|
+
"count": 1,
|
|
216
|
+
"step": 1
|
|
217
|
+
},
|
|
218
|
+
"side": "both",
|
|
219
|
+
"layer": "over",
|
|
220
|
+
"offset": {
|
|
221
|
+
"forward": 0,
|
|
222
|
+
"outward": 8
|
|
223
|
+
},
|
|
224
|
+
"angleDegrees": 52,
|
|
225
|
+
"scale": 1,
|
|
226
|
+
"source": 0.4,
|
|
227
|
+
"react": 1,
|
|
228
|
+
"recover": 30,
|
|
229
|
+
"wobble": 0.85
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
"legs": {
|
|
235
|
+
"section": "trunk",
|
|
236
|
+
"pairs": 0,
|
|
237
|
+
"reach": 17,
|
|
238
|
+
"spread": 0.78,
|
|
239
|
+
"lead": 0.5,
|
|
240
|
+
"fold": 0.5,
|
|
241
|
+
"jointBend": 1,
|
|
242
|
+
"jointLean": 0,
|
|
243
|
+
"jointLeanCenter": 0,
|
|
244
|
+
"sidePhase": 1,
|
|
245
|
+
"liftThreshold": 0.45,
|
|
246
|
+
"swingCycles": 0.21600000000000003,
|
|
247
|
+
"swingArc": 0.3,
|
|
248
|
+
"jitter": 0.3,
|
|
249
|
+
"skin": {
|
|
250
|
+
"limbPaint": "leg",
|
|
251
|
+
"limbWidth": 2.4,
|
|
252
|
+
"foot": {
|
|
253
|
+
"shape": "foot",
|
|
254
|
+
"paint": "foot",
|
|
255
|
+
"scale": 3,
|
|
256
|
+
"plantedScale": 1.35
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|