@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/relics.ts
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What is lying on the bottom, and what is coming out of it.
|
|
3
|
+
*
|
|
4
|
+
* Set pieces: a wreck, a volcanic smoker, and the two things down there that
|
|
5
|
+
* are jokes rather than scenery. Kept free of the DOM the way the rest of the
|
|
6
|
+
* ornament is.
|
|
7
|
+
*
|
|
8
|
+
* ## Rarity is the feature
|
|
9
|
+
*
|
|
10
|
+
* Everything here is placed by a roll of the seeded dice, and most rolls come
|
|
11
|
+
* up empty. That is deliberate and it is the only thing making any of it worth
|
|
12
|
+
* drawing: a wreck in every sea is set dressing, and a wreck in one sea out of
|
|
13
|
+
* three is something you found. The same water always has the same relics,
|
|
14
|
+
* because the seed decides, so it is a place rather than a slot machine.
|
|
15
|
+
*
|
|
16
|
+
* A consequence worth stating: most people will never see the chest. That is
|
|
17
|
+
* the correct outcome. Ornament that everybody sees every time has to justify
|
|
18
|
+
* itself to everybody every time, and this does not have to justify itself at
|
|
19
|
+
* all.
|
|
20
|
+
*
|
|
21
|
+
* ## The smoker
|
|
22
|
+
*
|
|
23
|
+
* A chimney, and a plume coming off it. The plume is the only part of the
|
|
24
|
+
* seabed that moves under its own steam rather than the water's, which is what
|
|
25
|
+
* makes a vent read as hot: everything else down there leans when the current
|
|
26
|
+
* leans, and this goes straight up regardless and then gets bent.
|
|
27
|
+
*
|
|
28
|
+
* ## The joke
|
|
29
|
+
*
|
|
30
|
+
* `chest` is the site's own, from `Marks.chest/1`: a chest with a laptop open
|
|
31
|
+
* on its lid, screen still lit. The site's rule for it is kept here, because
|
|
32
|
+
* the rule is most of why it works. It is never placed beside anything that
|
|
33
|
+
* explains it, and it is drawn small and half behind whatever is in front of
|
|
34
|
+
* it, for somebody who looks.
|
|
35
|
+
*
|
|
36
|
+
* The screen is the one thing in the entire seascape drawn at full weight. Down
|
|
37
|
+
* in the dark, under a hundred faint animals, there is a lit rectangle the size
|
|
38
|
+
* of a fingernail. Nothing else is allowed to be that bright, which is what
|
|
39
|
+
* makes it findable at all.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
import { makeNoise2, makeRandom } from "./perlin.ts"
|
|
43
|
+
import type { Point } from "./seabed.ts"
|
|
44
|
+
|
|
45
|
+
export type RelicKind = "block" | "chest" | "smoker" | "wreck"
|
|
46
|
+
|
|
47
|
+
export interface Relic {
|
|
48
|
+
/** 0 is as far off as this water goes, 1 is up against the glass. */
|
|
49
|
+
readonly depth: number
|
|
50
|
+
readonly kind: RelicKind
|
|
51
|
+
/** How far it has settled over, in radians. Nothing down there is level. */
|
|
52
|
+
readonly lean: number
|
|
53
|
+
/** px per unit of the drawing. */
|
|
54
|
+
readonly scale: number
|
|
55
|
+
readonly x: number
|
|
56
|
+
readonly y: number
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface Puff {
|
|
60
|
+
/** How far through its life it is, 0 new and 1 gone. */
|
|
61
|
+
age: number
|
|
62
|
+
r: number
|
|
63
|
+
/**
|
|
64
|
+
* This one's own share of the climb.
|
|
65
|
+
*
|
|
66
|
+
* Every puff used to rise at exactly the rate every other puff rose at, and
|
|
67
|
+
* a column of identical circles let go at an even beat is a string of beads,
|
|
68
|
+
* not a plume. One number each, drawn once, and the stack breaks up.
|
|
69
|
+
*/
|
|
70
|
+
readonly rise: number
|
|
71
|
+
x: number
|
|
72
|
+
y: number
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface Relics {
|
|
76
|
+
readonly plume: readonly Puff[]
|
|
77
|
+
readonly relics: readonly Relic[]
|
|
78
|
+
resize(width: number, height: number, floor: (x: number, depth?: number) => number): void
|
|
79
|
+
step(seconds: number): void
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface RelicsOptions {
|
|
83
|
+
/** The ground at x, at a given distance; `seabed.floorAt`. */
|
|
84
|
+
floor: (x: number, depth?: number) => number
|
|
85
|
+
height: number
|
|
86
|
+
seed: number
|
|
87
|
+
width: number
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The chance each relic is in this water at all.
|
|
92
|
+
*
|
|
93
|
+
* The wreck is the likeliest because it is the one that pays off as scenery
|
|
94
|
+
* even when you are not looking for it. The chest is the rarest by a distance,
|
|
95
|
+
* for the reason in the module note.
|
|
96
|
+
*/
|
|
97
|
+
const ODDS: Readonly<Record<RelicKind, number>> = {
|
|
98
|
+
block: 0.34,
|
|
99
|
+
chest: 0.1,
|
|
100
|
+
smoker: 0.5,
|
|
101
|
+
wreck: 0.4,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* How big each is, in px per unit of its own drawing, before depth takes its
|
|
106
|
+
* share.
|
|
107
|
+
*
|
|
108
|
+
* Per unit and not px across, so a renderer never has to know how wide any of
|
|
109
|
+
* these shapes happens to be. The wreck and the chest are both two units wide
|
|
110
|
+
* and the smoker is one, and that is between each drawing and its own comment.
|
|
111
|
+
*/
|
|
112
|
+
const SIZES: Readonly<Record<RelicKind, readonly [number, number]>> = {
|
|
113
|
+
block: [17, 26],
|
|
114
|
+
chest: [20, 29],
|
|
115
|
+
smoker: [38, 66],
|
|
116
|
+
wreck: [95, 170],
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** How far one may have settled over, in radians. */
|
|
120
|
+
const LEAN: Readonly<Record<RelicKind, number>> = {
|
|
121
|
+
block: 0.6,
|
|
122
|
+
chest: 0.12,
|
|
123
|
+
smoker: 0.05,
|
|
124
|
+
wreck: 0.16,
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* How far back a relic stands. Never up against the glass, never in the murk.
|
|
129
|
+
*
|
|
130
|
+
* The far end used to reach 0.35, which was harmless while every relic was
|
|
131
|
+
* planted on the near sand whatever it claimed its distance was. Standing them
|
|
132
|
+
* on the ground they are actually drawn at put them among the bands of hills,
|
|
133
|
+
* which run to about 0.75, and a wreck behind a rise is a wreck with its masts
|
|
134
|
+
* showing on a good day and nothing at all on most.
|
|
135
|
+
*
|
|
136
|
+
* Half buried is worth having and worth keeping rare: it is what a wreck seen
|
|
137
|
+
* across a slope really looks like. So the range starts in front of most of the
|
|
138
|
+
* ground rather than behind it, and the odd one that lands behind a crest is
|
|
139
|
+
* the odd one, not the usual case.
|
|
140
|
+
*/
|
|
141
|
+
const DEPTH_FAR = 0.6
|
|
142
|
+
|
|
143
|
+
const DEPTH_NEAR = 0.9
|
|
144
|
+
|
|
145
|
+
/** How often a smoker lets go of a puff, in seconds. */
|
|
146
|
+
const PUFF_GAP = 0.13
|
|
147
|
+
|
|
148
|
+
/** How much faster or slower than the rest one puff may climb. */
|
|
149
|
+
const PUFF_SLOWEST = 0.72
|
|
150
|
+
|
|
151
|
+
const PUFF_FASTEST = 1.28
|
|
152
|
+
|
|
153
|
+
/** How long one lasts, and how fast it climbs at first, in px a second. */
|
|
154
|
+
const PUFF_LIFE = 8
|
|
155
|
+
|
|
156
|
+
const PUFF_RISE = 52
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* How much it slows as it spreads, and how fast it swells.
|
|
160
|
+
*
|
|
161
|
+
* The swell is held down harder than looks right on paper. A puff's area goes
|
|
162
|
+
* up with the square of its radius while its weight only comes down with its
|
|
163
|
+
* age, so one that doubles in size has spread the same ink over four times the
|
|
164
|
+
* water and vanished; the plume then reads as a few dots at the vent and
|
|
165
|
+
* nothing above them, which is what it did at nine.
|
|
166
|
+
*/
|
|
167
|
+
const PUFF_DRAG = 0.62
|
|
168
|
+
|
|
169
|
+
const PUFF_SWELL = 4.5
|
|
170
|
+
|
|
171
|
+
/** How far the water carries a plume sideways, in px a second. */
|
|
172
|
+
const PUFF_SWAY = 16
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* How many features of the current fit across the box, and up it.
|
|
176
|
+
*
|
|
177
|
+
* Far more up than across, because that is the difference between a current
|
|
178
|
+
* and a wind. Water moves in layers: what is going one way at the floor is
|
|
179
|
+
* going another two metres above it, and a plume crossing those layers is
|
|
180
|
+
* pulled apart by them. Read at one feature per column height the whole plume
|
|
181
|
+
* gets one push and leans like smoke.
|
|
182
|
+
*/
|
|
183
|
+
const FIELD_CELLS = 2.4
|
|
184
|
+
|
|
185
|
+
const FIELD_ROWS = 5.5
|
|
186
|
+
|
|
187
|
+
const MIN_SPAN = 1
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* How many draws to throw away before the first decision is taken on one.
|
|
191
|
+
*
|
|
192
|
+
* The generator is an xorshift, and an xorshift's first outputs still carry the
|
|
193
|
+
* shape of the seed it was given: neighbouring seeds start with neighbouring
|
|
194
|
+
* numbers. Nothing else in the ornament notices, because everything else asks
|
|
195
|
+
* for hundreds of draws and only the first few are poor. This asks for four,
|
|
196
|
+
* and they decide the whole contents of the sea, so a run of seeds came out
|
|
197
|
+
* with a wreck and a smoker in almost every one of them and never much else.
|
|
198
|
+
*
|
|
199
|
+
* Discarding a handful first is the standard answer and it is enough here.
|
|
200
|
+
*/
|
|
201
|
+
const WARMUP = 12
|
|
202
|
+
|
|
203
|
+
export function createRelics(options: RelicsOptions): Relics {
|
|
204
|
+
const random = makeRandom(options.seed ^ 0x3c2f)
|
|
205
|
+
const shear = makeNoise2(options.seed ^ 0xa71c)
|
|
206
|
+
|
|
207
|
+
let width = Math.max(MIN_SPAN, options.width)
|
|
208
|
+
let height = Math.max(MIN_SPAN, options.height)
|
|
209
|
+
let floor = options.floor
|
|
210
|
+
let since = 0
|
|
211
|
+
let drift = 0
|
|
212
|
+
|
|
213
|
+
const relics: Relic[] = []
|
|
214
|
+
const plume: Puff[] = []
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* What is in this sea, from its own generator started afresh.
|
|
218
|
+
*
|
|
219
|
+
* Its own, and restarted every time, because what a sea contains has to be a
|
|
220
|
+
* pure function of its seed. Drawing from the shared stream meant a resize
|
|
221
|
+
* dealt a second hand: a window dragged wider, or a monitor coming back from
|
|
222
|
+
* sleep, and the wreck was gone and there was a chest instead. That is a
|
|
223
|
+
* wallpaper whose contents nobody can rely on having seen, and it is also why
|
|
224
|
+
* the same sea could not be looked at twice while any of this was being tuned.
|
|
225
|
+
*
|
|
226
|
+
* The warm-up is separate from that and needed for its own reason; see
|
|
227
|
+
* `WARMUP`.
|
|
228
|
+
*/
|
|
229
|
+
function place(): void {
|
|
230
|
+
const roll = makeRandom(options.seed ^ 0x8e11)
|
|
231
|
+
for (let spun = 0; spun < WARMUP; spun++) roll()
|
|
232
|
+
|
|
233
|
+
relics.length = 0
|
|
234
|
+
|
|
235
|
+
for (const kind of ["wreck", "smoker", "block", "chest"] as const) {
|
|
236
|
+
if (roll() >= ODDS[kind]) continue
|
|
237
|
+
|
|
238
|
+
const [least, most] = SIZES[kind]
|
|
239
|
+
const depth = DEPTH_FAR + roll() * (DEPTH_NEAR - DEPTH_FAR)
|
|
240
|
+
// Kept out of the corners: a wreck half off the edge of the picture is a
|
|
241
|
+
// wreck somebody cropped.
|
|
242
|
+
const x = width * (0.12 + roll() * 0.76)
|
|
243
|
+
|
|
244
|
+
relics.push({
|
|
245
|
+
depth,
|
|
246
|
+
kind,
|
|
247
|
+
lean: (roll() - 0.5) * LEAN[kind] * 2,
|
|
248
|
+
scale: (least + roll() * (most - least)) * depth,
|
|
249
|
+
x,
|
|
250
|
+
// Its own distance, which is the whole of the point. The ground is a
|
|
251
|
+
// different line at every distance and this asked for the one at the
|
|
252
|
+
// front, so a wreck standing a long way back was planted on the sand
|
|
253
|
+
// that belongs against the glass: a shape drawn at its own distance and
|
|
254
|
+
// sitting somewhere else entirely.
|
|
255
|
+
y: floor(x, depth),
|
|
256
|
+
})
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const smoker = (): Relic | undefined => relics.find((one) => one.kind === "smoker")
|
|
261
|
+
|
|
262
|
+
place()
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
plume,
|
|
266
|
+
relics,
|
|
267
|
+
|
|
268
|
+
resize(nextWidth, nextHeight, nextFloor) {
|
|
269
|
+
width = Math.max(MIN_SPAN, nextWidth)
|
|
270
|
+
height = Math.max(MIN_SPAN, nextHeight)
|
|
271
|
+
floor = nextFloor
|
|
272
|
+
plume.length = 0
|
|
273
|
+
place()
|
|
274
|
+
},
|
|
275
|
+
|
|
276
|
+
step(seconds) {
|
|
277
|
+
const dt = Math.min(Math.max(seconds, 0), 0.1)
|
|
278
|
+
drift += dt * 0.05
|
|
279
|
+
|
|
280
|
+
const vent = smoker()
|
|
281
|
+
if (vent) {
|
|
282
|
+
since += dt
|
|
283
|
+
if (since >= PUFF_GAP) {
|
|
284
|
+
since = 0
|
|
285
|
+
plume.push({
|
|
286
|
+
age: 0,
|
|
287
|
+
r: vent.scale * (0.07 + random() * 0.06),
|
|
288
|
+
rise: PUFF_SLOWEST + random() * (PUFF_FASTEST - PUFF_SLOWEST),
|
|
289
|
+
x: vent.x + (random() - 0.5) * vent.scale * 0.3,
|
|
290
|
+
y: vent.y - vent.scale * SMOKER_LIP,
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
for (let at = plume.length - 1; at >= 0; at--) {
|
|
296
|
+
const puff = plume[at]
|
|
297
|
+
if (!puff) continue
|
|
298
|
+
|
|
299
|
+
puff.age += dt / PUFF_LIFE
|
|
300
|
+
if (puff.age >= 1 || puff.y + puff.r < 0) {
|
|
301
|
+
plume.splice(at, 1)
|
|
302
|
+
continue
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Quick off the chimney, and nearly stalled by the top of its life.
|
|
306
|
+
// Hot water in cold water rises until it is no warmer than what it has
|
|
307
|
+
// climbed into, and then it stops and lies there; a plume that kept its
|
|
308
|
+
// speed to the end would be a jet, and a jet is a thing under pressure.
|
|
309
|
+
const climb = PUFF_RISE * puff.rise * (1 - PUFF_DRAG * puff.age)
|
|
310
|
+
puff.y -= climb * dt
|
|
311
|
+
|
|
312
|
+
// Spreading fastest where it is slowest, which is what turns the top of
|
|
313
|
+
// a plume into a layer rather than a point.
|
|
314
|
+
puff.r += PUFF_SWELL * (0.55 + puff.age) * dt
|
|
315
|
+
|
|
316
|
+
// A current, not a wind.
|
|
317
|
+
//
|
|
318
|
+
// This used to multiply the push by the puff's own age, so every puff
|
|
319
|
+
// was shoved harder than the one below it and the column leaned off in
|
|
320
|
+
// one direction and kept leaning: smoke off a chimney on a breezy day.
|
|
321
|
+
// Water does not do that. A current is the same push on everything in
|
|
322
|
+
// it, it varies far more with depth than with time, and it changes its
|
|
323
|
+
// mind, so what a plume does in it is lean one way, straighten, and
|
|
324
|
+
// lean the other. Reading the field finely up the column is what puts
|
|
325
|
+
// the snake in it; taking the age out is what stops it being weather.
|
|
326
|
+
puff.x +=
|
|
327
|
+
shear((puff.x / width) * FIELD_CELLS + drift, (puff.y / height) * FIELD_ROWS + drift) *
|
|
328
|
+
PUFF_SWAY *
|
|
329
|
+
dt
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* A wreck, in a hull two units long and lying on the origin.
|
|
337
|
+
*
|
|
338
|
+
* A silhouette and nothing else. At the weight anything down here is drawn,
|
|
339
|
+
* detail is wasted: what carries a wreck is the one line nothing in nature
|
|
340
|
+
* makes, which is a long straight sheer with a broken end on it. So the deck is
|
|
341
|
+
* straight, the bow is intact, and the stern is gone.
|
|
342
|
+
*
|
|
343
|
+
* The masts are what stop it reading as a rock. They are the only part that
|
|
344
|
+
* leaves the ground, and leaning verticals over a long horizontal suggest
|
|
345
|
+
* a ship at any size and any distance.
|
|
346
|
+
*/
|
|
347
|
+
export const WRECK =
|
|
348
|
+
"M-1 0 L-0.62 -0.2 L0.52 -0.24 Q0.86 -0.23 1 -0.06 L0.94 0.04 Q0.4 0.11 -0.3 0.09 Z " +
|
|
349
|
+
"M-0.62 -0.2 L-0.58 -0.34 L0.44 -0.37 L0.52 -0.24 Z " +
|
|
350
|
+
"M0.1 -0.36 L0.16 -0.92 L0.23 -0.36 Z " +
|
|
351
|
+
"M-0.3 -0.35 L-0.2 -0.76 L-0.16 -0.35 Z"
|
|
352
|
+
|
|
353
|
+
/** The spar across the standing mast, so the ship has rigging without any. */
|
|
354
|
+
export const WRECK_SPAR: readonly Point[] = [
|
|
355
|
+
{ x: 0.02, y: -0.74 },
|
|
356
|
+
{ x: 0.3, y: -0.66 },
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* A smoker, in a chimney one unit wide sitting on the origin.
|
|
361
|
+
*
|
|
362
|
+
* Tall and thin, and that proportion is the whole drawing. A chimney as wide as
|
|
363
|
+
* it is high is a mountain, which is what this was first: the thing a vent is
|
|
364
|
+
* has to read at a glance and there are only two facts available at this size,
|
|
365
|
+
* that it is narrow and that it is far taller than anything else on the floor.
|
|
366
|
+
*
|
|
367
|
+
* Not symmetrical, and stepped rather than smooth, because it built itself out
|
|
368
|
+
* of what it was pouring out. The lip is offset from the base for the same
|
|
369
|
+
* reason: nothing that grew from a leak grew straight.
|
|
370
|
+
*/
|
|
371
|
+
export const SMOKER =
|
|
372
|
+
"M-0.5 0 L-0.3 -0.7 L-0.22 -1.5 L-0.16 -2.1 L-0.2 -2.42 L-0.02 -2.5 " +
|
|
373
|
+
"L0.06 -2.16 L0.14 -2.34 L0.16 -1.9 L0.24 -1.2 L0.42 0 Z"
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* How far up the drawing the throat is, in the same units.
|
|
377
|
+
*
|
|
378
|
+
* Exported because the plume has to leave from it, and read off the drawing
|
|
379
|
+
* rather than guessed at. A plume that starts anywhere else comes out of the
|
|
380
|
+
* side of the chimney, and a chimney venting sideways is a hole in a rock.
|
|
381
|
+
*/
|
|
382
|
+
export const SMOKER_LIP = 2.45
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* A sunken code block, in a card two units wide, centred on the origin.
|
|
386
|
+
*
|
|
387
|
+
* The site's `Marks.code_block/1`: a card and three lines of unequal length
|
|
388
|
+
* with the middle one longest, which is the shape of a snippet at any size.
|
|
389
|
+
*
|
|
390
|
+
* The lines are paths and not rectangles, which is not a style choice. A
|
|
391
|
+
* renderer draws these inside a scale of a hundred or more, and a rectangle a
|
|
392
|
+
* fifth of a unit tall is rounded to a whole pixel before that scale is applied
|
|
393
|
+
* and comes out twenty units tall. Everything here is under a unit, so
|
|
394
|
+
* everything here is a path.
|
|
395
|
+
*/
|
|
396
|
+
export const BLOCK_CARD = "M-1 -0.73 L1 -0.73 L1 0.73 L-1 0.73 Z"
|
|
397
|
+
|
|
398
|
+
export const BLOCK_LINES: readonly string[] = [
|
|
399
|
+
"M-0.62 -0.45 L0.2 -0.45 L0.2 -0.29 L-0.62 -0.29 Z",
|
|
400
|
+
"M-0.62 -0.08 L0.74 -0.08 L0.74 0.08 L-0.62 0.08 Z",
|
|
401
|
+
"M-0.62 0.29 L-0.03 0.29 L-0.03 0.45 L-0.62 0.45 Z",
|
|
402
|
+
]
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* The chest, in a body two units wide sitting on the origin.
|
|
406
|
+
*
|
|
407
|
+
* `body` is the whole silhouette, trunk and domed lid in one closed path; the
|
|
408
|
+
* seam, the hasp and the laptop are separate because each is drawn in a
|
|
409
|
+
* different weight, and the screen is drawn in a weight nothing else in the sea
|
|
410
|
+
* is allowed.
|
|
411
|
+
*
|
|
412
|
+
* The trunk and the lid are one subpath and not two, which took a render to
|
|
413
|
+
* find: they meet along a shared edge, and two subpaths meeting along an edge
|
|
414
|
+
* are two subpaths a renderer is entitled to cancel against each other. What
|
|
415
|
+
* came out was a box with nothing on top of it.
|
|
416
|
+
*
|
|
417
|
+
* Wider than it is tall, with a shallow dome, which is the shape everybody's
|
|
418
|
+
* idea of a chest has.
|
|
419
|
+
*/
|
|
420
|
+
export const CHEST_BODY = "M-1 0 L-1 -0.62 Q-1 -1.12 0 -1.12 Q1 -1.12 1 -0.62 L1 0 Z"
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* The one line across it, at the seam between lid and trunk, and the hasp.
|
|
424
|
+
*
|
|
425
|
+
* One, and it took cutting three to see why. Every strap is subtracted from the
|
|
426
|
+
* silhouette in the colour of the water, so each one is a hole; the chest is
|
|
427
|
+
* fifty pixels wide in the scene, and three holes in fifty pixels is not a
|
|
428
|
+
* chest with straps on it, it is six small blocks in a row. What survives at
|
|
429
|
+
* that size is the seam, because the seam is the only line that says the thing
|
|
430
|
+
* opens.
|
|
431
|
+
*/
|
|
432
|
+
export const CHEST_BANDS: readonly string[] = ["M-1 -0.66 L1 -0.66 L1 -0.58 L-1 -0.58 Z"]
|
|
433
|
+
|
|
434
|
+
export const CHEST_LOCK = "M-0.13 -0.72 L0.13 -0.72 L0.13 -0.44 L-0.13 -0.44 Z"
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* The laptop open on the lid: the screen, the base under it, and the three
|
|
438
|
+
* lines still on the screen.
|
|
439
|
+
*
|
|
440
|
+
* Leaning back the way an open one does, and small against the chest, because
|
|
441
|
+
* what makes this land is finding it rather than being shown it.
|
|
442
|
+
*/
|
|
443
|
+
export const LAPTOP_SCREEN = "M-0.44 -1.94 L0.3 -2.04 L0.38 -1.2 L-0.36 -1.1 Z"
|
|
444
|
+
|
|
445
|
+
export const LAPTOP_BASE = "M-0.42 -1.14 L0.46 -1.24 L0.56 -1.1 L-0.34 -1 Z"
|
|
446
|
+
|
|
447
|
+
export const LAPTOP_LINES: readonly string[] = [
|
|
448
|
+
"M-0.3 -1.82 L0.02 -1.86 L0.02 -1.78 L-0.3 -1.74 Z",
|
|
449
|
+
"M-0.3 -1.66 L0.16 -1.72 L0.16 -1.64 L-0.3 -1.58 Z",
|
|
450
|
+
"M-0.3 -1.5 L-0.08 -1.53 L-0.08 -1.45 L-0.3 -1.42 Z",
|
|
451
|
+
]
|