@codincod/ornament 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 +661 -0
- package/README.md +62 -2
- package/package.json +35 -3
- package/src/biome.ts +157 -0
- package/src/canvas/flat.ts +336 -0
- package/src/caustics.ts +81 -0
- package/src/census.ts +262 -0
- package/src/cephalopods.ts +1041 -0
- package/src/cloud.ts +308 -0
- package/src/crags.ts +974 -0
- package/src/drift.ts +435 -0
- package/src/eels.ts +667 -0
- package/src/fish_shape.ts +410 -0
- package/src/flora.ts +1955 -0
- package/src/flow_field.ts +491 -0
- package/src/jellies.ts +1794 -0
- package/src/nemos.ts +606 -0
- package/src/paint/bed.ts +231 -0
- package/src/paint/colour.ts +86 -0
- package/src/paint/frame.ts +204 -0
- package/src/paint/ink.ts +134 -0
- package/src/paint/life.ts +611 -0
- package/src/paint/light.ts +132 -0
- package/src/paint/pen.ts +225 -0
- package/src/paint/rock.ts +325 -0
- package/src/paint/sea.ts +809 -0
- package/src/paint/shade.ts +109 -0
- package/src/paint/sky.ts +377 -0
- package/src/paint/specimen.ts +300 -0
- package/src/paint/svg.ts +326 -0
- package/src/paint/trace.ts +164 -0
- package/src/passers.ts +730 -0
- package/src/perlin.ts +168 -0
- package/src/plenty.ts +65 -0
- package/src/puffers.ts +510 -0
- package/src/rays.ts +225 -0
- package/src/reef.ts +945 -0
- package/src/relics.ts +451 -0
- package/src/seabed.ts +525 -0
- package/src/shoal.ts +1658 -0
- package/src/sizes.ts +86 -0
- package/src/sun.ts +500 -0
- package/src/swarm.ts +587 -0
- package/src/visitors.ts +1936 -0
- package/src/walkers.ts +861 -0
package/src/walkers.ts
ADDED
|
@@ -0,0 +1,861 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What walks on the bottom: crabs and starfish.
|
|
3
|
+
*
|
|
4
|
+
* The bed grows things and now it has animals living on it, kept free of the
|
|
5
|
+
* DOM the way the rest of the ornament is. A plant is rooted and everything it
|
|
6
|
+
* does is the water doing it; these two are the other case. They are on the
|
|
7
|
+
* ground, they go where they decide to go, and the current has no say in
|
|
8
|
+
* either.
|
|
9
|
+
*
|
|
10
|
+
* ## Why they are not in `flora.ts`
|
|
11
|
+
*
|
|
12
|
+
* A thing that walks is not a thing that is rooted, and the two want opposite
|
|
13
|
+
* machinery. A plant is a strand recut from a field every step and it never
|
|
14
|
+
* moves, so nothing about it accumulates. A walker has a position it carries
|
|
15
|
+
* from one step to the next, which is a different kind of object however
|
|
16
|
+
* similar the drawings come out.
|
|
17
|
+
*
|
|
18
|
+
* ## Why the bottom needed them
|
|
19
|
+
*
|
|
20
|
+
* Everything else down there is scenery. Kelp leans, coral holds still, and a
|
|
21
|
+
* bed of both is a place with nothing living in it, which the eye reads as a
|
|
22
|
+
* diagram of a seabed. One animal going about its business at the bottom of the
|
|
23
|
+
* picture is what makes the rest of it a floor rather than a pattern, and it
|
|
24
|
+
* costs a handful of lines.
|
|
25
|
+
*
|
|
26
|
+
* ## A crab
|
|
27
|
+
*
|
|
28
|
+
* It goes sideways, which is the whole of what says crab before anything else
|
|
29
|
+
* about the drawing does. Most of its day it is not going anywhere: it stands,
|
|
30
|
+
* it works at the sand, and then it crosses a stretch quickly and stops again.
|
|
31
|
+
* That is the shape a small animal on an open floor actually has, and it is
|
|
32
|
+
* also what makes the crossings worth watching.
|
|
33
|
+
*
|
|
34
|
+
* The gait runs off distance rather than off the clock. A leg cycle driven by
|
|
35
|
+
* time carries on swinging while the animal stands still, which reads as a
|
|
36
|
+
* crab running on the spot; driven by how far it has gone, the legs stop when
|
|
37
|
+
* it stops and hurry when it hurries, for free.
|
|
38
|
+
*
|
|
39
|
+
* ## A starfish
|
|
40
|
+
*
|
|
41
|
+
* It creeps. The number is not a compromise: a starfish moves about as fast as
|
|
42
|
+
* a minute hand, so what it has instead of a gait is its arms, which reach and
|
|
43
|
+
* shorten on their own clocks. Over a sitting it will have gone somewhere, and
|
|
44
|
+
* nobody will have seen it go.
|
|
45
|
+
*
|
|
46
|
+
* It is drawn squashed, because it is lying on the ground rather than standing
|
|
47
|
+
* on it. The ground climbs the picture as it goes back, so the sand is seen
|
|
48
|
+
* from a shallow angle above, and a star lying flat on it is a star seen from
|
|
49
|
+
* that angle. Drawn round it would be a starfish stuck to the glass.
|
|
50
|
+
*
|
|
51
|
+
* ## Nobody tells a crab anything
|
|
52
|
+
*
|
|
53
|
+
* There is no conductor down here. The water is the place everything is in and
|
|
54
|
+
* the register of what is in it, and an animal reads that register and decides
|
|
55
|
+
* for itself; nothing is fired at it. So a crab is handed `about`, a way of
|
|
56
|
+
* asking what else is out there, and what it does with the answer is its own
|
|
57
|
+
* business. Hand it nothing and it goes about its day.
|
|
58
|
+
*
|
|
59
|
+
* What it does is freeze. A crab on open sand cannot outrun anything worth
|
|
60
|
+
* running from, so its first answer is to stop being a moving thing, and its
|
|
61
|
+
* second, when whatever it is gets close enough, is to bolt for the edge of the
|
|
62
|
+
* picture. That order matters: a crab that bolted at the first shadow would be
|
|
63
|
+
* a crab that has never met one.
|
|
64
|
+
*
|
|
65
|
+
* The two answers are to different questions, which is why the water reports
|
|
66
|
+
* size and menace separately. Anything big enough and near enough will stop a
|
|
67
|
+
* crab dead, turtle or shark, because a thing that has not seen you is a thing
|
|
68
|
+
* you keep it that way. What decides whether it then runs is whether the thing
|
|
69
|
+
* looks like it hunts. Something enormous and harmless directly overhead will
|
|
70
|
+
* still move it, because a crab under a turtle is a crab about to be stood on.
|
|
71
|
+
*
|
|
72
|
+
* A starfish does nothing at all, which is not an omission. Its answer to a
|
|
73
|
+
* predator takes hours, and an animal reacting on a timescale nobody is
|
|
74
|
+
* watching is an animal that does not react.
|
|
75
|
+
*
|
|
76
|
+
* ## The drawings
|
|
77
|
+
*
|
|
78
|
+
* The same contract the octopus keeps, so a renderer that can draw one can draw
|
|
79
|
+
* these: a path in a drawing one unit wide sitting on the origin, plus lines in
|
|
80
|
+
* that same drawing, and `size` is what a unit is worth in px. The origin is
|
|
81
|
+
* the sand under the animal, which is what lets a renderer put it at `x`, `y`
|
|
82
|
+
* and be done.
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
import { abreast, type Presence } from "./biome.ts"
|
|
86
|
+
import { makeRandom } from "./perlin.ts"
|
|
87
|
+
import type { Point } from "./seabed.ts"
|
|
88
|
+
import { BED_OFF, drawnAt } from "./sizes.ts"
|
|
89
|
+
|
|
90
|
+
export type WalkerKind = "crab" | "starfish"
|
|
91
|
+
|
|
92
|
+
export interface Walker {
|
|
93
|
+
/**
|
|
94
|
+
* The body, as a path in a drawing one unit wide sitting on the origin.
|
|
95
|
+
*
|
|
96
|
+
* Recut every step. A carapace has no shape to change, so what moves it is
|
|
97
|
+
* the bob; a starfish is all body, so its arms are the only thing it has.
|
|
98
|
+
*/
|
|
99
|
+
body: string
|
|
100
|
+
/**
|
|
101
|
+
* How many times this walker has redrawn itself.
|
|
102
|
+
*
|
|
103
|
+
* The only thing a renderer has to watch. While it holds, `body`, `legs`,
|
|
104
|
+
* `x`, `y` and `facing` are what they already were, so a renderer keeping its
|
|
105
|
+
* own drawing keeps one that is still true and does no work. A crab spends
|
|
106
|
+
* most of its day standing, so most of them hold most of the time.
|
|
107
|
+
*/
|
|
108
|
+
cut: number
|
|
109
|
+
/** 0 is as far off as this water goes, 1 is up against the glass. */
|
|
110
|
+
readonly depth: number
|
|
111
|
+
/** Which way it is going. A crab leads with a side; a starfish has no front
|
|
112
|
+
* at all and keeps this only to say which way it is creeping. */
|
|
113
|
+
facing: number
|
|
114
|
+
readonly kind: WalkerKind
|
|
115
|
+
/** The legs and the claws, in the same drawing. Empty for a starfish. */
|
|
116
|
+
legs: Point[][]
|
|
117
|
+
/** px per unit of the drawing. */
|
|
118
|
+
readonly size: number
|
|
119
|
+
x: number
|
|
120
|
+
y: number
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface Walkers {
|
|
124
|
+
/**
|
|
125
|
+
* A box of a new size, and the ground that came with it.
|
|
126
|
+
*
|
|
127
|
+
* The height is taken and not read. Nothing here ever leaves the ground, so
|
|
128
|
+
* the only thing a taller box changes is where the ground is, and that
|
|
129
|
+
* arrives as `floor`. It is in the signature because every other layer's
|
|
130
|
+
* resize has that shape and a renderer resizes all of them in a row.
|
|
131
|
+
*/
|
|
132
|
+
resize(width: number, height: number, floor: (x: number, depth?: number) => number): void
|
|
133
|
+
step(seconds: number): void
|
|
134
|
+
readonly walkers: readonly Walker[]
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface WalkersOptions {
|
|
138
|
+
/**
|
|
139
|
+
* What else is in the water, asked for once a step.
|
|
140
|
+
*
|
|
141
|
+
* Left out, nothing is: a floor with no register to read is a floor whose
|
|
142
|
+
* animals have nothing to be frightened of, which is the state a scene with
|
|
143
|
+
* no shark in it is in anyway.
|
|
144
|
+
*/
|
|
145
|
+
about?: () => readonly Presence[]
|
|
146
|
+
crabs?: number
|
|
147
|
+
/** The ground at x, at a given distance; `seabed.floorAt`. An animal that
|
|
148
|
+
* asked for the sand at the front while standing at the back would be an
|
|
149
|
+
* animal buried up to its shell in the hillside. */
|
|
150
|
+
floor: (x: number, depth?: number) => number
|
|
151
|
+
seed: number
|
|
152
|
+
starfish?: number
|
|
153
|
+
/**
|
|
154
|
+
* How far a walker may travel from its last drawing before it redraws, in px.
|
|
155
|
+
*
|
|
156
|
+
* `FloraOptions.tolerance` for animals that walk, and the same bargain. A
|
|
157
|
+
* crab standing still is free, one crossing a stretch costs what it always
|
|
158
|
+
* did, and in between the drawing arrives in steps of this size. At nothing
|
|
159
|
+
* every walker redraws on every step, which is how it behaved before.
|
|
160
|
+
*/
|
|
161
|
+
tolerance?: number
|
|
162
|
+
width: number
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The ends of a crab's shell across, and of a starfish's span tip to tip, in
|
|
167
|
+
* metres.
|
|
168
|
+
*
|
|
169
|
+
* Real animals off the sand, turned into a share of the box by `sizes.ts` at
|
|
170
|
+
* the distance the floor lies at. Written in px they were a fraction of what
|
|
171
|
+
* they should have been, and the fault could not be seen from inside this file:
|
|
172
|
+
* nine px is a defensible crab right up until a fish the length of your hand
|
|
173
|
+
* swims over it at six times its size. The two of them are near enough one
|
|
174
|
+
* another in the water, so they are near enough one another here.
|
|
175
|
+
*
|
|
176
|
+
* The shell rather than the animal, because the shell is what a drawing here is
|
|
177
|
+
* a unit of. A crab reaches about twice this once its legs and its claws are
|
|
178
|
+
* out, which is where the animal a reader actually sees comes from.
|
|
179
|
+
*/
|
|
180
|
+
const CRAB_SMALLEST = 0.06
|
|
181
|
+
|
|
182
|
+
const CRAB_LARGEST = 0.14
|
|
183
|
+
|
|
184
|
+
const STARFISH_SMALLEST = 0.18
|
|
185
|
+
|
|
186
|
+
const STARFISH_LARGEST = 0.34
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* How much of a walker's drawn size is its distance.
|
|
190
|
+
*
|
|
191
|
+
* The share the rest of the scene uses. Scaled by depth outright, the far end
|
|
192
|
+
* of the range is a tenth of the near end, and a tenth of a crab is a speck;
|
|
193
|
+
* what distance is for down here is weight rather than size.
|
|
194
|
+
*/
|
|
195
|
+
const DEPTH_SIZE = 0.55
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* How far back they go.
|
|
199
|
+
*
|
|
200
|
+
* As far as the bed grows, and that is the point of them. The far ground is the
|
|
201
|
+
* part of the picture that reads as bare, and a plant does not fix it: that far
|
|
202
|
+
* back a plant is a few px of a faint line, which the haze takes first. What
|
|
203
|
+
* fixes bare ground is something with a body. A shell and a star are both a
|
|
204
|
+
* shape with an outline, and an outline survives being drawn small and faint.
|
|
205
|
+
*/
|
|
206
|
+
const DEPTH_FAR = 0.12
|
|
207
|
+
|
|
208
|
+
const DEPTH_NEAR = 1
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* How hard a starfish leans towards the back of the water when it is placed.
|
|
212
|
+
*
|
|
213
|
+
* A crab is mostly legs, which is to say mostly lines, and it belongs wherever
|
|
214
|
+
* it happens to be. A starfish is a disc, and a disc is worth most where a line
|
|
215
|
+
* has stopped reading. It is a lean rather than a rule, since one at the front
|
|
216
|
+
* is the only one anybody sees the arms of.
|
|
217
|
+
*/
|
|
218
|
+
const STAR_BACK = 1.7
|
|
219
|
+
|
|
220
|
+
/** How far past the side one goes before it comes back on the other. */
|
|
221
|
+
const MARGIN = 1.4
|
|
222
|
+
|
|
223
|
+
/** How fast a crab crosses, in its own widths a second, and how much faster or
|
|
224
|
+
* slower than that one of them is. */
|
|
225
|
+
const SCUTTLE = 2.6
|
|
226
|
+
|
|
227
|
+
const HASTE = 0.45
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* How long a crab stands and how long it goes, in seconds, and how often a stop
|
|
231
|
+
* turns it round.
|
|
232
|
+
*
|
|
233
|
+
* Standing takes most of it. An animal that crossed the picture continuously
|
|
234
|
+
* would be a shuttle, and the stopping is what makes a crossing something that
|
|
235
|
+
* happened rather than something that is always happening.
|
|
236
|
+
*/
|
|
237
|
+
const STAND_LEAST = 3.5
|
|
238
|
+
|
|
239
|
+
const STAND_SPAN = 9
|
|
240
|
+
|
|
241
|
+
const GO_LEAST = 0.8
|
|
242
|
+
|
|
243
|
+
const GO_SPAN = 2.6
|
|
244
|
+
|
|
245
|
+
const TURN_ODDS = 0.45
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* How much bigger than a crab a thing has to be before it is minded, how far
|
|
249
|
+
* off it is minded from as a share of its own size, and how fast the fright
|
|
250
|
+
* fades once it has gone.
|
|
251
|
+
*
|
|
252
|
+
* The first two are the rule `nemos.ts` uses, because it is the right rule and
|
|
253
|
+
* two animals in one water should be frightened of the same things. Something
|
|
254
|
+
* a crab's own size is another crab.
|
|
255
|
+
*/
|
|
256
|
+
const MINDS = 1.6
|
|
257
|
+
|
|
258
|
+
const NOTICE = 3.2
|
|
259
|
+
|
|
260
|
+
const FRIGHT_FADE = 3.5
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* How much of a bolt something with no menace about it can still provoke.
|
|
264
|
+
*
|
|
265
|
+
* A quarter. `nemos.ts` weighs its fright the same way and for the same reason:
|
|
266
|
+
* a shape that has never eaten anybody is not nothing when it is on top of you,
|
|
267
|
+
* and a sea where a turtle and a shark were the same event is a sea where
|
|
268
|
+
* nothing that happens means anything.
|
|
269
|
+
*/
|
|
270
|
+
const BULK = 0.25
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* How frightened a crab has to be before it stops, and before it runs.
|
|
274
|
+
*
|
|
275
|
+
* A long way apart. Freezing is the whole of what a small animal on open ground
|
|
276
|
+
* has, and the bolt is what is left when freezing has plainly not worked.
|
|
277
|
+
*/
|
|
278
|
+
const FREEZE_AT = 0.05
|
|
279
|
+
|
|
280
|
+
const BOLT_AT = 0.55
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* How near a thing has to be, whatever it looks like, before a crab gets out
|
|
284
|
+
* from under it.
|
|
285
|
+
*
|
|
286
|
+
* Nearly touching, and it is the only reading here that ignores menace
|
|
287
|
+
* entirely. A crab under a turtle is a crab about to be stood on, and nothing
|
|
288
|
+
* about the turtle's intentions makes that better.
|
|
289
|
+
*/
|
|
290
|
+
const SQUASH_AT = 0.88
|
|
291
|
+
|
|
292
|
+
/** How much faster than a walk a bolt is. */
|
|
293
|
+
const BOLT = 3.4
|
|
294
|
+
|
|
295
|
+
/** How fast a starfish creeps, in its own spans a second, and how far off that
|
|
296
|
+
* one of them is. A minute hand, and the arithmetic is the same. */
|
|
297
|
+
const CREEP = 0.008
|
|
298
|
+
|
|
299
|
+
const DAWDLE = 0.6
|
|
300
|
+
|
|
301
|
+
/** How long a starfish holds a direction, in seconds. Nothing about this animal
|
|
302
|
+
* is in a hurry, and a starfish that changed its mind often would be a leaf. */
|
|
303
|
+
const HOLD_LEAST = 40
|
|
304
|
+
|
|
305
|
+
const HOLD_SPAN = 90
|
|
306
|
+
|
|
307
|
+
/** How high the shell rides above the sand, and how far it bobs as the legs
|
|
308
|
+
* work. A shell that rode on the ground would be a stone with legs. */
|
|
309
|
+
const RIDE = 0.24
|
|
310
|
+
|
|
311
|
+
const BOB = 0.035
|
|
312
|
+
|
|
313
|
+
/** How many legs a side carries, how far one strides, and how far it lifts. */
|
|
314
|
+
const LEGS = 4
|
|
315
|
+
|
|
316
|
+
/** What the far side's legs keep of the near side's reach, and how far up the
|
|
317
|
+
* picture its feet stand. The ground behind something is drawn higher than the
|
|
318
|
+
* ground it is standing on, and a foot that ignored that is a foot in a hole. */
|
|
319
|
+
const AWAY = 0.66
|
|
320
|
+
|
|
321
|
+
const BEHIND = 0.05
|
|
322
|
+
|
|
323
|
+
const STRIDE = 0.1
|
|
324
|
+
|
|
325
|
+
const LIFT = 0.06
|
|
326
|
+
|
|
327
|
+
/** How far a crab's gait comes round for one width travelled. Two cycles, so a
|
|
328
|
+
* leg is not covering half the animal's own width in a stride. */
|
|
329
|
+
const GAIT = Math.PI * 4
|
|
330
|
+
|
|
331
|
+
/** How many arms a starfish has, how far the web between them comes in, and how
|
|
332
|
+
* finely the outline is cut. */
|
|
333
|
+
/** How far a walker travels before it is worth redrawing, in px, by default. */
|
|
334
|
+
const TOLERANCE = 0.25
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* How far a crab's foot travels for a radian of its gait, in the drawing.
|
|
338
|
+
*
|
|
339
|
+
* Read off `crabLegs` rather than guessed at. A foot sits at `swing * STRIDE`
|
|
340
|
+
* across and `-max(0, swing) * LIFT` up, and a sine cannot change faster than
|
|
341
|
+
* its own angle, so no part of a leg outruns this. It is the whole of what
|
|
342
|
+
* changes when a crab works its legs without going anywhere.
|
|
343
|
+
*/
|
|
344
|
+
const GAIT_REACH = Math.hypot(STRIDE, LIFT)
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* How much of an arm's length is the reach that makes it creep, halved.
|
|
348
|
+
*
|
|
349
|
+
* A starfish is drawn one unit across, so an arm tip sits about half a unit out
|
|
350
|
+
* and travels about half of whatever its length does. Its length is
|
|
351
|
+
* `odd * (1 + sin(clock) * ARM_REACH)`, and each arm keeps its own clock, so
|
|
352
|
+
* what a starfish is capable of in a second is the fastest of them.
|
|
353
|
+
*/
|
|
354
|
+
const ARM_TIP = 0.5
|
|
355
|
+
|
|
356
|
+
const ARMS = 5
|
|
357
|
+
|
|
358
|
+
const WEB = 0.44
|
|
359
|
+
|
|
360
|
+
const RIM = 44
|
|
361
|
+
|
|
362
|
+
/** How much of its span an arm may be short or long of the rest, and how far it
|
|
363
|
+
* reaches and pulls back as it goes. No two arms of one animal agree. */
|
|
364
|
+
const ODD_ARM = 0.22
|
|
365
|
+
|
|
366
|
+
const ARM_REACH = 0.12
|
|
367
|
+
|
|
368
|
+
/** How fast an arm works through its own reach, slowest to fastest. */
|
|
369
|
+
const ARM_SLOWEST = 0.12
|
|
370
|
+
|
|
371
|
+
const ARM_FASTEST = 0.34
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* How much a starfish is squashed, lying on the sand.
|
|
375
|
+
*
|
|
376
|
+
* Nearly half. It is the one drawing here that is being seen from above rather
|
|
377
|
+
* than from the side, and the ground it is lying on is a slope going away from
|
|
378
|
+
* the reader; this is that slope's share of it. Drawn round it is a starfish
|
|
379
|
+
* stuck to the inside of the glass.
|
|
380
|
+
*/
|
|
381
|
+
const FLATTEN = 0.46
|
|
382
|
+
|
|
383
|
+
const MIN_SPAN = 1
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* What a crab has made of the water this moment: how alarming the worst thing
|
|
387
|
+
* in it is, how much of that is something that hunts, and where it was.
|
|
388
|
+
*/
|
|
389
|
+
interface Seen {
|
|
390
|
+
chased: number
|
|
391
|
+
from: number
|
|
392
|
+
near: number
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* The walker as it stood when it was last drawn.
|
|
397
|
+
*
|
|
398
|
+
* Everything the drawing was made from, so how far it has wandered since is
|
|
399
|
+
* arithmetic on it. Against the last drawing rather than the last step, since a
|
|
400
|
+
* crab that shuffled and came back has not moved.
|
|
401
|
+
*/
|
|
402
|
+
interface Drawn {
|
|
403
|
+
readonly facing: number
|
|
404
|
+
/** Seconds since the drawing was made, which is all a starfish needs. */
|
|
405
|
+
since: number
|
|
406
|
+
readonly stride: number
|
|
407
|
+
readonly x: number
|
|
408
|
+
readonly y: number
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** What one walker is doing, alongside the animal itself. */
|
|
412
|
+
interface Doing {
|
|
413
|
+
/** Where each arm is in its own reach. Empty for a crab. */
|
|
414
|
+
readonly arms: number[]
|
|
415
|
+
/** How far through the current bout it is, in seconds. */
|
|
416
|
+
at: number
|
|
417
|
+
/** How much of the fright is something that looks like it hunts. */
|
|
418
|
+
chased: number
|
|
419
|
+
/** How far this one's fastest arm carries its tip in a second, in the
|
|
420
|
+
* drawing. Nought for a crab, which has no arms and a gait instead. */
|
|
421
|
+
readonly creep: number
|
|
422
|
+
/** How frightened it is, 0 easy and 1 with the thing on top of it. */
|
|
423
|
+
fright: number
|
|
424
|
+
/** Whether it is going anywhere at the moment. */
|
|
425
|
+
going: boolean
|
|
426
|
+
/** How long and how odd each arm is. Empty for a crab. */
|
|
427
|
+
readonly odd: readonly number[]
|
|
428
|
+
/** How fast it goes when it is going, in px a second. */
|
|
429
|
+
readonly pace: number
|
|
430
|
+
/** How far each arm gets through its reach in a second. Empty for a crab. */
|
|
431
|
+
readonly rates: readonly number[]
|
|
432
|
+
/** How long this bout runs, in seconds. */
|
|
433
|
+
span: number
|
|
434
|
+
/** How far through the gait it is, in radians. */
|
|
435
|
+
stride: number
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* A crab's shell, in a drawing one unit wide sitting on the origin.
|
|
440
|
+
*
|
|
441
|
+
* Wider than it is tall, which is the half of a crab that is not its legs. The
|
|
442
|
+
* `bob` lifts it as the legs work, and it is small enough that nobody will name
|
|
443
|
+
* it: what it is for is that the shell and the legs are one animal rather than
|
|
444
|
+
* a drawing with lines under it.
|
|
445
|
+
*/
|
|
446
|
+
export function crabShell(bob: number): string {
|
|
447
|
+
const at = (-RIDE - 0.22 + Math.sin(bob) * BOB).toFixed(3)
|
|
448
|
+
const up = (-RIDE - 0.46 + Math.sin(bob) * BOB).toFixed(3)
|
|
449
|
+
const low = (-RIDE + 0.02 + Math.sin(bob) * BOB).toFixed(3)
|
|
450
|
+
|
|
451
|
+
return [
|
|
452
|
+
`M-0.5 ${at}`,
|
|
453
|
+
`Q-0.48 ${up} 0 ${up}`,
|
|
454
|
+
`Q0.48 ${up} 0.5 ${at}`,
|
|
455
|
+
`Q0.46 ${low} 0 ${low}`,
|
|
456
|
+
`Q-0.46 ${low} -0.5 ${at}`,
|
|
457
|
+
"Z",
|
|
458
|
+
].join(" ")
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/** The shell with the bob out of it, for anything wanting a still one. */
|
|
462
|
+
export const CRAB_SHELL = crabShell(0)
|
|
463
|
+
|
|
464
|
+
/** How a crab is standing: which way it leads, and where it is in its gait. */
|
|
465
|
+
export interface CrabPose {
|
|
466
|
+
readonly facing: number
|
|
467
|
+
readonly stride: number
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* The legs and the claws, in the same drawing as the shell.
|
|
472
|
+
*
|
|
473
|
+
* A leg is a hip, a knee above the shell and a foot on the sand, which is the
|
|
474
|
+
* arch that says crab rather than insect. They work in two groups, so half the
|
|
475
|
+
* animal is planted whenever the other half is swinging, and the swing is a
|
|
476
|
+
* step forward and a lift rather than a wave: a foot that rose without going
|
|
477
|
+
* anywhere is a crab treading water.
|
|
478
|
+
*
|
|
479
|
+
* The claws lead, because a crab goes sideways and holds them in front of the
|
|
480
|
+
* side it is going to. They are the one part of it drawn to be recognised at
|
|
481
|
+
* this size.
|
|
482
|
+
*/
|
|
483
|
+
export function crabLegs(pose: CrabPose): Point[][] {
|
|
484
|
+
const legs: Point[][] = []
|
|
485
|
+
|
|
486
|
+
for (let side = -1; side <= 1; side += 2) {
|
|
487
|
+
// The four on the far side of the animal, drawn shorter and standing
|
|
488
|
+
// closer in. There is no second weight to draw them at, so what says they
|
|
489
|
+
// are behind the shell is that they are foreshortened, which is what the
|
|
490
|
+
// far side of a standing thing actually does. Which side that is only
|
|
491
|
+
// changes at a stop, for the reason the octopus turns at a stop.
|
|
492
|
+
const away = side === -pose.facing ? AWAY : 1
|
|
493
|
+
|
|
494
|
+
for (let at = 0; at < LEGS; at++) {
|
|
495
|
+
const hip = { x: side * (0.44 - at * 0.05), y: -RIDE - 0.34 + at * 0.08 }
|
|
496
|
+
const seat = (0.5 + at * 0.13) * away
|
|
497
|
+
|
|
498
|
+
// Half of them a stride behind the other half. Every leg swinging at once
|
|
499
|
+
// is a crab hopping, and every leg planted at once is a crab sliding.
|
|
500
|
+
const swing = Math.sin(pose.stride + (at % 2 === 0 ? 0 : Math.PI) + (side < 0 ? Math.PI : 0))
|
|
501
|
+
const foot = {
|
|
502
|
+
x: side * seat + swing * STRIDE * pose.facing,
|
|
503
|
+
y: -Math.max(0, swing) * LIFT * away - (away < 1 ? BEHIND : 0),
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
legs.push([
|
|
507
|
+
hip,
|
|
508
|
+
{ x: (hip.x + foot.x) / 2 + side * 0.07, y: (-RIDE - 0.36 - at * 0.02) * away },
|
|
509
|
+
foot,
|
|
510
|
+
])
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Out in front of the side it is going to, and folded rather than straight: a
|
|
515
|
+
// claw held out at arm's length is a crab surrendering.
|
|
516
|
+
for (const up of [0, 1]) {
|
|
517
|
+
const lead = pose.facing
|
|
518
|
+
const rise = -RIDE - 0.1 - up * 0.13
|
|
519
|
+
|
|
520
|
+
legs.push([
|
|
521
|
+
{ x: lead * 0.36, y: rise },
|
|
522
|
+
{ x: lead * (0.74 + up * 0.05), y: rise + 0.04 },
|
|
523
|
+
{ x: lead * (1.02 + up * 0.06), y: rise - 0.06 },
|
|
524
|
+
{ x: lead * (0.88 + up * 0.05), y: rise - 0.2 },
|
|
525
|
+
])
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return legs
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* A starfish, as one closed outline in a drawing one unit across.
|
|
533
|
+
*
|
|
534
|
+
* Arms rather than points. A starfish drawn with a straight edge from tip to
|
|
535
|
+
* tip is a sheriff's badge, and what a real one has is a thick arm coming out
|
|
536
|
+
* of a disc and a deep round web between it and the next. `WEB` is where that
|
|
537
|
+
* web comes in to, and the whole difference between the two drawings is that
|
|
538
|
+
* number.
|
|
539
|
+
*
|
|
540
|
+
* `reach` is each arm's own length, which is where every one of these stops
|
|
541
|
+
* being a stamp of the same shape: an animal whose arms all agreed would be a
|
|
542
|
+
* cut-out, and a real one has one arm short from an argument it lost.
|
|
543
|
+
*/
|
|
544
|
+
export function starfishBody(reach: readonly number[]): string {
|
|
545
|
+
const arms = Math.max(1, reach.length)
|
|
546
|
+
|
|
547
|
+
// Seated on the longest arm it currently has, so it sits on the sand rather
|
|
548
|
+
// than through it, the way every other drawing here does. The seat shifts as
|
|
549
|
+
// the arms work, which is a settling nobody will name and is cheaper than
|
|
550
|
+
// deciding what the ground in front of it would have hidden.
|
|
551
|
+
const seat = Math.max(...reach) * 0.5 * FLATTEN
|
|
552
|
+
|
|
553
|
+
const path: string[] = []
|
|
554
|
+
for (let at = 0; at <= RIM; at++) {
|
|
555
|
+
const turn = (at / RIM) * Math.PI * 2
|
|
556
|
+
const lobe = (1 + Math.cos(turn * arms)) / 2
|
|
557
|
+
const arm = reach[Math.round((turn * arms) / (Math.PI * 2)) % arms] ?? 1
|
|
558
|
+
const out = (WEB + (1 - WEB) * lobe ** 0.7) * arm * 0.5
|
|
559
|
+
|
|
560
|
+
const x = (Math.sin(turn) * out).toFixed(3)
|
|
561
|
+
const y = (-seat - Math.cos(turn) * out * FLATTEN).toFixed(3)
|
|
562
|
+
path.push(`${at === 0 ? "M" : "L"}${x} ${y}`)
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
path.push("Z")
|
|
566
|
+
return path.join(" ")
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
export function createWalkers(options: WalkersOptions): Walkers {
|
|
570
|
+
const random = makeRandom(options.seed ^ 0x3c4a)
|
|
571
|
+
|
|
572
|
+
let width = Math.max(MIN_SPAN, options.width)
|
|
573
|
+
let floor = options.floor
|
|
574
|
+
|
|
575
|
+
const walkers: Walker[] = []
|
|
576
|
+
const doings: Doing[] = []
|
|
577
|
+
|
|
578
|
+
const tolerance = Math.max(0, options.tolerance ?? TOLERANCE)
|
|
579
|
+
|
|
580
|
+
/** What each walker was drawn from, or null while it never has been. */
|
|
581
|
+
const held: (Drawn | null)[] = []
|
|
582
|
+
|
|
583
|
+
function born(kind: WalkerKind): void {
|
|
584
|
+
const crab = kind === "crab"
|
|
585
|
+
const back = crab ? random() : random() ** STAR_BACK
|
|
586
|
+
const depth = DEPTH_FAR + back * (DEPTH_NEAR - DEPTH_FAR)
|
|
587
|
+
const across = crab
|
|
588
|
+
? CRAB_SMALLEST + random() * (CRAB_LARGEST - CRAB_SMALLEST)
|
|
589
|
+
: STARFISH_SMALLEST + random() * (STARFISH_LARGEST - STARFISH_SMALLEST)
|
|
590
|
+
const span = drawnAt(across, BED_OFF) * width
|
|
591
|
+
const size = span * (1 - DEPTH_SIZE + DEPTH_SIZE * depth)
|
|
592
|
+
const x = random() * width
|
|
593
|
+
|
|
594
|
+
const odd: number[] = []
|
|
595
|
+
const arms: number[] = []
|
|
596
|
+
const rates: number[] = []
|
|
597
|
+
if (!crab) {
|
|
598
|
+
for (let at = 0; at < ARMS; at++) {
|
|
599
|
+
odd.push(1 - ODD_ARM + random() * ODD_ARM * 2)
|
|
600
|
+
arms.push(random() * Math.PI * 2)
|
|
601
|
+
rates.push(ARM_SLOWEST + random() * (ARM_FASTEST - ARM_SLOWEST))
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// Part way through whatever it is doing already. A floor where every animal
|
|
606
|
+
// set off on the same frame is a floor that was switched on.
|
|
607
|
+
const going = crab ? random() < 0.3 : true
|
|
608
|
+
const run = crab ? bout(going) : HOLD_LEAST + random() * HOLD_SPAN
|
|
609
|
+
|
|
610
|
+
let quickest = 0
|
|
611
|
+
for (let at = 0; at < odd.length; at++) {
|
|
612
|
+
quickest = Math.max(quickest, (odd[at] ?? 0) * (rates[at] ?? 0) * ARM_REACH * ARM_TIP)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
doings.push({
|
|
616
|
+
arms,
|
|
617
|
+
at: random() * run,
|
|
618
|
+
chased: 0,
|
|
619
|
+
creep: quickest,
|
|
620
|
+
fright: 0,
|
|
621
|
+
going,
|
|
622
|
+
odd,
|
|
623
|
+
pace: crab
|
|
624
|
+
? size * SCUTTLE * (1 - HASTE + random() * HASTE * 2)
|
|
625
|
+
: size * CREEP * (1 - DAWDLE + random() * DAWDLE * 2),
|
|
626
|
+
rates,
|
|
627
|
+
span: run,
|
|
628
|
+
stride: random() * Math.PI * 2,
|
|
629
|
+
})
|
|
630
|
+
|
|
631
|
+
walkers.push({
|
|
632
|
+
body: "",
|
|
633
|
+
cut: 0,
|
|
634
|
+
depth,
|
|
635
|
+
facing: random() < 0.5 ? -1 : 1,
|
|
636
|
+
kind,
|
|
637
|
+
legs: [],
|
|
638
|
+
size,
|
|
639
|
+
x,
|
|
640
|
+
y: floor(x, depth),
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
held.push(null)
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/** How long a crab stands, or how long it goes. */
|
|
647
|
+
function bout(going: boolean): number {
|
|
648
|
+
return going ? GO_LEAST + random() * GO_SPAN : STAND_LEAST + random() * STAND_SPAN
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* One animal, a moment on.
|
|
653
|
+
*
|
|
654
|
+
* A crab's gait is wound by the ground it covered rather than by the time
|
|
655
|
+
* that passed, so its legs stop when it does. That is one line and it is the
|
|
656
|
+
* difference between an animal walking and a sprite playing an animation.
|
|
657
|
+
*/
|
|
658
|
+
/**
|
|
659
|
+
* How frightened this one is by what is in the water, right now.
|
|
660
|
+
*
|
|
661
|
+
* Bigger than it is, and near enough, where near is measured against the
|
|
662
|
+
* size of the thing rather than in px: a shark is a shark from further off
|
|
663
|
+
* than a bream is. `nemos.ts` minds the water by the same rule, which is
|
|
664
|
+
* what keeps two animals in one sea frightened of the same things.
|
|
665
|
+
*/
|
|
666
|
+
function minded(one: Walker, water: readonly Presence[]): Seen {
|
|
667
|
+
const seen: Seen = { chased: 0, from: one.x, near: 0 }
|
|
668
|
+
|
|
669
|
+
for (const thing of water) {
|
|
670
|
+
if (thing.size < one.size * MINDS) continue
|
|
671
|
+
|
|
672
|
+
const reach = thing.size * NOTICE
|
|
673
|
+
const away = Math.hypot(one.x - thing.x, one.y - thing.y)
|
|
674
|
+
if (away >= reach) continue
|
|
675
|
+
|
|
676
|
+
// Weighed by how nearly abreast the two are, because a screen has two
|
|
677
|
+
// distances and this water has three: a shark cruising past the glass is
|
|
678
|
+
// nowhere near a crab back in the murk, however neatly they line up.
|
|
679
|
+
const near = (1 - away / reach) * abreast(one.depth, thing.depth)
|
|
680
|
+
if (near <= seen.near) continue
|
|
681
|
+
|
|
682
|
+
seen.chased = near * (BULK + (thing.menace ?? 0) * (1 - BULK))
|
|
683
|
+
seen.from = thing.x
|
|
684
|
+
seen.near = near
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
return seen
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function carry(at: number, seconds: number, water: readonly Presence[]): void {
|
|
691
|
+
const one = walkers[at]
|
|
692
|
+
const doing = doings[at]
|
|
693
|
+
if (!one || !doing) return
|
|
694
|
+
|
|
695
|
+
doing.at += seconds
|
|
696
|
+
|
|
697
|
+
const was = held[at]
|
|
698
|
+
if (was) was.since += seconds
|
|
699
|
+
|
|
700
|
+
if (one.kind === "crab") {
|
|
701
|
+
const seen = minded(one, water)
|
|
702
|
+
doing.fright = Math.max(0, Math.max(doing.fright - seconds / FRIGHT_FADE, seen.near))
|
|
703
|
+
doing.chased = Math.max(0, Math.max(doing.chased - seconds / FRIGHT_FADE, seen.chased))
|
|
704
|
+
|
|
705
|
+
// Stop being a moving thing, and run only once that has plainly not
|
|
706
|
+
// worked. Both answers are taken before the bout it was in gets a say,
|
|
707
|
+
// and the bout is left where it was: what it was doing before the
|
|
708
|
+
// shadow came over is what it goes back to afterwards.
|
|
709
|
+
if (doing.chased > BOLT_AT || doing.fright > SQUASH_AT) {
|
|
710
|
+
one.facing = one.x < seen.from ? -1 : 1
|
|
711
|
+
const gone = doing.pace * BOLT * seconds * one.facing
|
|
712
|
+
one.x += gone
|
|
713
|
+
doing.stride += (Math.abs(gone) / one.size) * GAIT
|
|
714
|
+
settle(one)
|
|
715
|
+
return
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (doing.fright > FREEZE_AT) {
|
|
719
|
+
settle(one)
|
|
720
|
+
return
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (doing.at >= doing.span) {
|
|
724
|
+
doing.going = !doing.going
|
|
725
|
+
doing.at = 0
|
|
726
|
+
doing.span = bout(doing.going)
|
|
727
|
+
if (!doing.going && random() < TURN_ODDS) one.facing = -one.facing
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
if (doing.going) {
|
|
731
|
+
const gone = doing.pace * seconds * one.facing
|
|
732
|
+
one.x += gone
|
|
733
|
+
doing.stride += (Math.abs(gone) / one.size) * GAIT
|
|
734
|
+
}
|
|
735
|
+
} else {
|
|
736
|
+
if (doing.at >= doing.span) {
|
|
737
|
+
doing.at = 0
|
|
738
|
+
doing.span = HOLD_LEAST + random() * HOLD_SPAN
|
|
739
|
+
one.facing = random() < 0.5 ? -1 : 1
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
one.x += doing.pace * seconds * one.facing
|
|
743
|
+
for (let arm = 0; arm < doing.arms.length; arm++) {
|
|
744
|
+
doing.arms[arm] = (doing.arms[arm] ?? 0) + (doing.rates[arm] ?? 0) * seconds
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
settle(one)
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Off one side and on at the other, and standing on the ground it is over.
|
|
753
|
+
*
|
|
754
|
+
* What the water does with everything else that crosses it. Every path
|
|
755
|
+
* through a step ends here, including the one a frightened crab takes, since
|
|
756
|
+
* a crab that ran off the edge of the picture and stayed there would be a
|
|
757
|
+
* crab that was frightened once.
|
|
758
|
+
*/
|
|
759
|
+
function settle(one: Walker): void {
|
|
760
|
+
const past = one.size * MARGIN
|
|
761
|
+
if (one.x < -past) one.x += width + past * 2
|
|
762
|
+
if (one.x > width + past) one.x -= width + past * 2
|
|
763
|
+
|
|
764
|
+
one.y = floor(one.x, one.depth)
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* How far this walker can have travelled since it was last drawn.
|
|
769
|
+
*
|
|
770
|
+
* The animal moves as a whole and its legs move under it, and both have to be
|
|
771
|
+
* in here because a renderer holds one drawing for the two of them. The whole
|
|
772
|
+
* is `x` and `y` and is exact. The legs are a bound: a crab's foot cannot
|
|
773
|
+
* outrun `GAIT_REACH` for a radian of gait, and a starfish's arm cannot
|
|
774
|
+
* outrun `creep` for a second of creeping, and neither is a measurement of
|
|
775
|
+
* the drawing because making one would cost the drawing.
|
|
776
|
+
*
|
|
777
|
+
* A crab that turns is redrawn whatever the arithmetic says. Its far legs are
|
|
778
|
+
* the ones that shorten, so a mirrored crab is a different animal from the
|
|
779
|
+
* front and nothing continuous describes the change.
|
|
780
|
+
*/
|
|
781
|
+
function stir(at: number): number {
|
|
782
|
+
const one = walkers[at]
|
|
783
|
+
const doing = doings[at]
|
|
784
|
+
const was = held[at]
|
|
785
|
+
if (!one || !doing || !was) return Number.POSITIVE_INFINITY
|
|
786
|
+
if (was.facing !== one.facing) return Number.POSITIVE_INFINITY
|
|
787
|
+
|
|
788
|
+
const worked = GAIT_REACH * Math.abs(doing.stride - was.stride) + doing.creep * was.since
|
|
789
|
+
|
|
790
|
+
return Math.hypot(one.x - was.x, one.y - was.y) + one.size * worked
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/** Redraw one where it currently stands. */
|
|
794
|
+
function draw(at: number): void {
|
|
795
|
+
const one = walkers[at]
|
|
796
|
+
const doing = doings[at]
|
|
797
|
+
if (!one || !doing) return
|
|
798
|
+
|
|
799
|
+
held[at] = {
|
|
800
|
+
facing: one.facing,
|
|
801
|
+
since: 0,
|
|
802
|
+
stride: doing.stride,
|
|
803
|
+
x: one.x,
|
|
804
|
+
y: one.y,
|
|
805
|
+
}
|
|
806
|
+
one.cut++
|
|
807
|
+
|
|
808
|
+
if (one.kind === "crab") {
|
|
809
|
+
one.body = crabShell(doing.stride)
|
|
810
|
+
one.legs = crabLegs({ facing: one.facing, stride: doing.stride })
|
|
811
|
+
return
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
one.body = starfishBody(
|
|
815
|
+
doing.odd.map((odd, arm) => odd * (1 + Math.sin(doing.arms[arm] ?? 0) * ARM_REACH)),
|
|
816
|
+
)
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
function stock(): void {
|
|
820
|
+
walkers.length = 0
|
|
821
|
+
doings.length = 0
|
|
822
|
+
held.length = 0
|
|
823
|
+
|
|
824
|
+
for (let made = 0; made < Math.max(0, options.crabs ?? 0); made++) born("crab")
|
|
825
|
+
for (let made = 0; made < Math.max(0, options.starfish ?? 0); made++) born("starfish")
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
function advance(seconds: number): void {
|
|
829
|
+
const step = Math.min(Math.max(seconds, 0), 0.1)
|
|
830
|
+
const water = options.about?.() ?? []
|
|
831
|
+
|
|
832
|
+
for (let at = 0; at < walkers.length; at++) {
|
|
833
|
+
carry(at, step, water)
|
|
834
|
+
if (stir(at) >= tolerance) draw(at)
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
stock()
|
|
839
|
+
advance(0)
|
|
840
|
+
|
|
841
|
+
return {
|
|
842
|
+
resize(nextWidth, _height, nextFloor) {
|
|
843
|
+
const scale = Math.max(MIN_SPAN, nextWidth) / width
|
|
844
|
+
width = Math.max(MIN_SPAN, nextWidth)
|
|
845
|
+
floor = nextFloor
|
|
846
|
+
|
|
847
|
+
for (let at = 0; at < walkers.length; at++) {
|
|
848
|
+
const one = walkers[at]
|
|
849
|
+
if (!one) continue
|
|
850
|
+
|
|
851
|
+
one.x *= scale
|
|
852
|
+
one.y = floor(one.x, one.depth)
|
|
853
|
+
draw(at)
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
|
|
857
|
+
step: advance,
|
|
858
|
+
|
|
859
|
+
walkers,
|
|
860
|
+
}
|
|
861
|
+
}
|