@echomem/mcp 1.4.8 → 1.4.9

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.
Files changed (36) hide show
  1. package/README.md +23 -3
  2. package/assets/canonical-scorer/README.md +18 -0
  3. package/assets/canonical-scorer/analyze-10-problems.mjs +857 -0
  4. package/assets/canonical-scorer/build-session-waste-dashboard.mjs +1628 -0
  5. package/assets/canonical-scorer/golden_anchors.mjs +83 -0
  6. package/assets/canonical-scorer/optimizable_detail.mjs +633 -0
  7. package/dist/city/chaos-to-clarity-pencil.html +582 -0
  8. package/dist/city/echo-ai-city-only.html +1104 -105
  9. package/dist/city/echo-ai-city-only.template.html +1104 -105
  10. package/dist/city/pencil-pie-generator.html +883 -0
  11. package/dist/city/pencil-webgl-landscape.html +1239 -0
  12. package/dist/city/spatial-fan-story.html +479 -0
  13. package/dist/codex-session-files.js +283 -0
  14. package/dist/codex-sync.js +7 -2
  15. package/dist/context-analysis/canonical-golden.js +47 -0
  16. package/dist/context-analysis/claude-native-canonical.js +1193 -0
  17. package/dist/context-analysis/vendored-canonical.js +793 -0
  18. package/dist/context-analysis/workspace-report.js +1838 -0
  19. package/dist/context-metrics/calculate.js +56 -0
  20. package/dist/context-metrics/model-limits.js +26 -0
  21. package/dist/context-metrics/types.js +1 -0
  22. package/dist/forensics-10-problems.js +7 -6
  23. package/dist/forensics.js +863 -132
  24. package/dist/hud/adapters.js +8 -4
  25. package/dist/hud/metric.js +13 -4
  26. package/dist/hud/monitor.js +135 -16
  27. package/dist/hud/web.js +344 -298
  28. package/dist/index.js +7 -3
  29. package/dist/local-data-paths.js +87 -0
  30. package/dist/migrate.js +37 -29
  31. package/dist/report.js +101 -40
  32. package/dist/setup-page.js +3290 -196
  33. package/dist/setup-preview.js +245 -0
  34. package/dist/setup.js +432 -34
  35. package/package.json +5 -4
  36. package/templates/echomem-recall.md +2 -2
@@ -0,0 +1,582 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Chaos to Clarity — Pencil Study</title>
7
+ <style>
8
+ * { box-sizing: border-box; }
9
+ html, body { min-height: 100%; }
10
+ body {
11
+ margin: 0;
12
+ display: grid;
13
+ place-items: center;
14
+ padding: clamp(12px, 4vw, 48px);
15
+ background: #d8d4ca;
16
+ }
17
+ .sheet {
18
+ position: relative;
19
+ width: min(92vw, 900px);
20
+ aspect-ratio: 1;
21
+ overflow: hidden;
22
+ background: #f2eee4;
23
+ box-shadow: 0 24px 70px rgba(39, 38, 31, .18), 0 2px 5px rgba(39, 38, 31, .12);
24
+ }
25
+ canvas {
26
+ display: block;
27
+ width: 100%;
28
+ height: 100%;
29
+ }
30
+ </style>
31
+ </head>
32
+ <body>
33
+ <main class="sheet" aria-label="混乱经过透镜转化为清晰方向的铅笔插画">
34
+ <canvas id="art" width="1200" height="1200"></canvas>
35
+ </main>
36
+
37
+ <script>
38
+ const canvas = document.getElementById("art");
39
+ const g = canvas.getContext("2d");
40
+ const TAU = Math.PI * 2;
41
+ const ink = "#292a25";
42
+ const paper = "#f2eee4";
43
+
44
+ function randomFactory(seed) {
45
+ return function random() {
46
+ let t = seed += 0x6D2B79F5;
47
+ t = Math.imul(t ^ t >>> 15, t | 1);
48
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
49
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
50
+ };
51
+ }
52
+
53
+ function pencil(path, width = 2, alpha = .72, repeats = 2, seed = 1) {
54
+ const random = randomFactory(seed);
55
+ for (let i = 0; i < repeats; i++) {
56
+ g.save();
57
+ g.translate((random() - .5) * 2.1, (random() - .5) * 1.6);
58
+ path();
59
+ g.strokeStyle = ink;
60
+ g.globalAlpha = alpha / Math.max(1, repeats * .7);
61
+ g.lineWidth = width + random() * .7;
62
+ g.lineCap = "round";
63
+ g.lineJoin = "round";
64
+ g.stroke();
65
+ g.restore();
66
+ }
67
+ }
68
+
69
+ function line(x1, y1, x2, y2, width = 1.5, alpha = .6, seed = 1) {
70
+ pencil(() => {
71
+ g.beginPath();
72
+ g.moveTo(x1, y1);
73
+ g.lineTo(x2, y2);
74
+ }, width, alpha, 2, seed);
75
+ }
76
+
77
+ function poly(points, close = false, width = 1.8, alpha = .7, seed = 1) {
78
+ pencil(() => {
79
+ g.beginPath();
80
+ g.moveTo(points[0][0], points[0][1]);
81
+ for (let i = 1; i < points.length; i++) g.lineTo(points[i][0], points[i][1]);
82
+ if (close) g.closePath();
83
+ }, width, alpha, 2, seed);
84
+ }
85
+
86
+ function ellipse(cx, cy, rx, ry, width = 1.7, alpha = .68, seed = 1) {
87
+ pencil(() => {
88
+ g.beginPath();
89
+ g.ellipse(cx, cy, rx, ry, 0, 0, TAU);
90
+ }, width, alpha, 2, seed);
91
+ }
92
+
93
+ function arrow(x1, y1, x2, y2, seed = 1, alpha = .68) {
94
+ line(x1, y1, x2, y2, 1.5, alpha, seed);
95
+ const angle = Math.atan2(y2 - y1, x2 - x1);
96
+ const size = 12;
97
+ poly([
98
+ [x2 - Math.cos(angle - .55) * size, y2 - Math.sin(angle - .55) * size],
99
+ [x2, y2],
100
+ [x2 - Math.cos(angle + .55) * size, y2 - Math.sin(angle + .55) * size]
101
+ ], false, 1.5, alpha, seed + 2);
102
+ }
103
+
104
+ /*
105
+ PencilLight is the reusable drawing model for this document.
106
+
107
+ 1. Curve tangent = direction of the form.
108
+ 2. Curve normal = candidate side for light or shadow.
109
+ 3. Depth controls width, contrast and spacing: far is thin/light/open;
110
+ near is heavier/darker/closer.
111
+ 4. Shadow is made from continuous pressure strokes following the form,
112
+ never from mechanical dashed fills.
113
+ 5. A ribbon is a perspective surface: its two edges come from the curve
114
+ normal, while its width grows toward the viewer.
115
+ */
116
+ const PencilLight = Object.freeze({
117
+ light: { x: -.82, y: -.57 },
118
+
119
+ cubic(p0, p1, p2, p3, steps = 36) {
120
+ const points = [];
121
+ for (let i = 0; i <= steps; i++) {
122
+ const t = i / steps;
123
+ const u = 1 - t;
124
+ points.push({
125
+ x: u*u*u*p0.x + 3*u*u*t*p1.x + 3*u*t*t*p2.x + t*t*t*p3.x,
126
+ y: u*u*u*p0.y + 3*u*u*t*p1.y + 3*u*t*t*p2.y + t*t*t*p3.y,
127
+ depth: t
128
+ });
129
+ }
130
+ return points;
131
+ },
132
+
133
+ frames(points) {
134
+ return points.map((point, i) => {
135
+ const a = points[Math.max(0, i - 1)];
136
+ const b = points[Math.min(points.length - 1, i + 1)];
137
+ const tx = b.x - a.x;
138
+ const ty = b.y - a.y;
139
+ const length = Math.hypot(tx, ty) || 1;
140
+ return { ...point, tx: tx / length, ty: ty / length, nx: -ty / length, ny: tx / length };
141
+ });
142
+ },
143
+
144
+ curve(points, { width = 1.4, alpha = .58, seed = 1, repeats = 2 } = {}) {
145
+ pencil(() => {
146
+ g.beginPath();
147
+ g.moveTo(points[0].x, points[0].y);
148
+ for (let i = 1; i < points.length; i++) g.lineTo(points[i].x, points[i].y);
149
+ }, width, alpha, repeats, seed);
150
+ },
151
+
152
+ ribbon(points, widthAt, { seed = 1 } = {}) {
153
+ const frames = this.frames(points);
154
+ const left = [];
155
+ const right = [];
156
+ frames.forEach((frame, i) => {
157
+ const half = widthAt(frame.depth, i) * .5;
158
+ left.push({ x: frame.x + frame.nx * half, y: frame.y + frame.ny * half });
159
+ right.push({ x: frame.x - frame.nx * half, y: frame.y - frame.ny * half });
160
+ });
161
+
162
+ g.beginPath();
163
+ g.moveTo(left[0].x, left[0].y);
164
+ for (let i = 1; i < left.length; i++) g.lineTo(left[i].x, left[i].y);
165
+ for (let i = right.length - 1; i >= 0; i--) g.lineTo(right[i].x, right[i].y);
166
+ g.closePath();
167
+ g.fillStyle = "rgba(244,241,233,.96)";
168
+ g.fill();
169
+
170
+ this.curve(left, { width: 1.2, alpha: .54, seed });
171
+ this.curve(right, { width: 1.2, alpha: .54, seed: seed + 1 });
172
+
173
+ // The edge whose normal points away from the light receives pressure.
174
+ const mid = frames[Math.floor(frames.length * .58)];
175
+ const shadowSign = mid.nx * -this.light.x + mid.ny * -this.light.y >= 0 ? 1 : -1;
176
+ const shadowEdge = shadowSign > 0 ? left : right;
177
+ for (let band = 0; band < 4; band++) {
178
+ const shaded = shadowEdge.map((point, i) => {
179
+ const frame = frames[i];
180
+ const depth = frame.depth;
181
+ const distance = 2 + band * (2.2 + depth * 1.8);
182
+ return {
183
+ x: point.x + frame.nx * shadowSign * distance,
184
+ y: point.y + frame.ny * shadowSign * distance
185
+ };
186
+ });
187
+ this.curve(shaded, {
188
+ width: .75 + band * .08,
189
+ alpha: .34 - band * .055,
190
+ seed: seed + 20 + band,
191
+ repeats: 1
192
+ });
193
+ }
194
+ },
195
+
196
+ slopeFacet({ ridge, foot, spread, strokes, darkness, seed }) {
197
+ const random = randomFactory(seed);
198
+ for (let i = 0; i < strokes; i++) {
199
+ const lane = strokes === 1 ? 0 : i / (strokes - 1) - .5;
200
+ const start = {
201
+ x: ridge.x + lane * spread,
202
+ y: ridge.y + Math.abs(lane) * spread * .28
203
+ };
204
+ const end = {
205
+ x: foot.x + lane * spread * 1.5,
206
+ y: foot.y - random() * 8
207
+ };
208
+ const points = this.cubic(
209
+ start,
210
+ { x: start.x + (end.x - start.x) * .22, y: start.y + (end.y - start.y) * .4 },
211
+ { x: start.x + (end.x - start.x) * .72, y: start.y + (end.y - start.y) * .82 },
212
+ end,
213
+ 18
214
+ );
215
+ this.curve(points, {
216
+ width: .65 + darkness * .55,
217
+ alpha: .12 + darkness * .3,
218
+ seed: seed + i,
219
+ repeats: 1
220
+ });
221
+ }
222
+ },
223
+
224
+ meshSurface({ height, project, columns = 17, rows = 12, samples = 58, seed = 1 }) {
225
+ const clamp = value => Math.max(0, Math.min(1, value));
226
+
227
+ // Depth rows behave like soft contour lines across the terrain.
228
+ for (let row = 0; row < rows; row++) {
229
+ const v = row / (rows - 1);
230
+ const points = [];
231
+ for (let i = 0; i <= samples; i++) {
232
+ const u = -1 + i / samples * 2;
233
+ points.push(project(u, v, height(u, v)));
234
+ }
235
+ this.curve(points, {
236
+ width: .52 + v * .42,
237
+ alpha: .13 + v * .16,
238
+ seed: seed + row,
239
+ repeats: 1
240
+ });
241
+ }
242
+
243
+ // Flow lines run continuously from the far ridge toward the viewer.
244
+ // Their pressure is derived from surface slope relative to the light.
245
+ for (let column = 0; column < columns; column++) {
246
+ const u = -1 + column / (columns - 1) * 2;
247
+ const points = [];
248
+ for (let i = 0; i <= samples; i++) {
249
+ const v = i / samples;
250
+ points.push(project(u, v, height(u, v)));
251
+ }
252
+ const slope = height(Math.min(1, u + .025), .42) - height(Math.max(-1, u - .025), .42);
253
+ const darkness = clamp(.48 + slope * 2.4);
254
+ this.curve(points, {
255
+ width: .55 + darkness * .36,
256
+ alpha: .15 + darkness * .2,
257
+ seed: seed + 100 + column,
258
+ repeats: 1
259
+ });
260
+ }
261
+ }
262
+ });
263
+
264
+ function drawPaper() {
265
+ const random = randomFactory(8041);
266
+ g.fillStyle = paper;
267
+ g.fillRect(0, 0, canvas.width, canvas.height);
268
+ const colors = ["rgba(58,55,46,.025)", "rgba(255,255,255,.065)"];
269
+ for (let pass = 0; pass < 2; pass++) {
270
+ g.beginPath();
271
+ for (let i = 0; i < 4200; i++) {
272
+ const x = random() * canvas.width;
273
+ const y = random() * canvas.height;
274
+ const w = .35 + random() * 1.5;
275
+ g.rect(x, y, w, w * (.4 + random()));
276
+ }
277
+ g.fillStyle = colors[pass];
278
+ g.fill();
279
+ }
280
+ g.beginPath();
281
+ for (let i = 0; i < 180; i++) {
282
+ const x = random() * canvas.width;
283
+ const y = random() * canvas.height;
284
+ g.moveTo(x, y);
285
+ g.lineTo(x + 8 + random() * 24, y + (random() - .5) * 3);
286
+ }
287
+ g.strokeStyle = "rgba(69,65,54,.028)";
288
+ g.lineWidth = .55;
289
+ g.stroke();
290
+ }
291
+
292
+ function dottedJourney() {
293
+ g.save();
294
+ g.strokeStyle = "rgba(41,42,37,.45)";
295
+ g.lineWidth = 1.5;
296
+ g.setLineDash([3, 11]);
297
+ g.lineCap = "round";
298
+ g.beginPath();
299
+ g.moveTo(88, 130);
300
+ g.bezierCurveTo(55, 240, 232, 225, 178, 330);
301
+ g.bezierCurveTo(130, 430, 348, 366, 336, 510);
302
+ g.bezierCurveTo(325, 635, 118, 608, 182, 742);
303
+ g.bezierCurveTo(225, 822, 336, 788, 397, 862);
304
+ g.stroke();
305
+ g.restore();
306
+ }
307
+
308
+ function drawChaos() {
309
+ const random = randomFactory(3319);
310
+ const cx = 238;
311
+ const cy = 550;
312
+ for (let layer = 0; layer < 3; layer++) {
313
+ g.beginPath();
314
+ const strands = 17 + layer * 7;
315
+ for (let strand = 0; strand < strands; strand++) {
316
+ let x = cx + (random() - .5) * (174 - layer * 22);
317
+ let y = cy + (random() - .5) * (184 - layer * 20);
318
+ g.moveTo(x, y);
319
+ const steps = 8 + Math.floor(random() * 7);
320
+ for (let step = 0; step < steps; step++) {
321
+ const pull = .06 + layer * .018;
322
+ x += (random() - .5) * (72 - layer * 9) + (cx - x) * pull;
323
+ y += (random() - .5) * (68 - layer * 8) + (cy - y) * pull;
324
+ g.lineTo(x, y);
325
+ }
326
+ }
327
+ g.strokeStyle = `rgba(35,36,32,${.11 + layer * .045})`;
328
+ g.lineWidth = .74 + layer * .14;
329
+ g.lineCap = "round";
330
+ g.stroke();
331
+ }
332
+ for (let i = 0; i < 7; i++) {
333
+ const x = cx + (random() - .5) * 200;
334
+ const y = cy + (random() - .5) * 200;
335
+ ellipse(x, y, 16 + random() * 46, 10 + random() * 34, .9, .24, 500 + i);
336
+ }
337
+ }
338
+
339
+ function drawQuestion(x, y, s, seed) {
340
+ pencil(() => {
341
+ g.beginPath();
342
+ g.moveTo(x - s * .25, y - s * .28);
343
+ g.bezierCurveTo(x - s * .1, y - s * .66, x + s * .55, y - s * .48, x + s * .34, y - s * .08);
344
+ g.bezierCurveTo(x + s * .22, y + s * .12, x, y + s * .12, x, y + s * .38);
345
+ }, 1.6, .57, 2, seed);
346
+ ellipse(x, y + s * .62, 2.4, 2.4, 1.2, .65, seed + 1);
347
+ }
348
+
349
+ function drawGear(x, y, r, seed) {
350
+ ellipse(x, y, r * .58, r * .58, 1.4, .55, seed);
351
+ ellipse(x, y, r * .16, r * .16, 1.2, .55, seed + 1);
352
+ for (let i = 0; i < 9; i++) {
353
+ const a = i / 9 * TAU;
354
+ line(x + Math.cos(a) * r * .63, y + Math.sin(a) * r * .63,
355
+ x + Math.cos(a) * r, y + Math.sin(a) * r, 1.4, .55, seed + i + 2);
356
+ }
357
+ }
358
+
359
+ function drawCloud(x, y, s, seed) {
360
+ pencil(() => {
361
+ g.beginPath();
362
+ g.moveTo(x - s * .65, y + s * .2);
363
+ g.bezierCurveTo(x - s * .82, y - s * .18, x - s * .42, y - s * .4, x - s * .16, y - s * .24);
364
+ g.bezierCurveTo(x, y - s * .72, x + s * .5, y - s * .55, x + s * .48, y - s * .2);
365
+ g.bezierCurveTo(x + s * .86, y - s * .18, x + s * .82, y + s * .25, x + s * .55, y + s * .26);
366
+ g.lineTo(x - s * .65, y + s * .2);
367
+ }, 1.4, .5, 2, seed);
368
+ }
369
+
370
+ function drawDoodles() {
371
+ drawQuestion(40, 298, 32, 10);
372
+ drawQuestion(122, 756, 25, 11);
373
+ drawQuestion(390, 430, 20, 12);
374
+ drawGear(210, 206, 26, 20);
375
+ drawCloud(67, 377, 30, 31);
376
+ drawCloud(120, 850, 22, 32);
377
+ poly([[252,137],[306,115],[278,171],[268,143],[252,137]], true, 1.4, .6, 40);
378
+ line(268,143,306,115,1.1,.46,41);
379
+ poly([[389,207],[398,226],[419,229],[402,241],[407,262],[389,250],[372,263],[377,241],[359,229],[381,226]], true, 1.2, .55, 50);
380
+ poly([[296,825],[315,790],[322,812],[344,810],[318,853],[314,827]], true, 1.5, .62, 60);
381
+ poly([[94,698],[123,684],[145,699],[142,725],[110,730],[91,715]], false, 1.3, .45, 70);
382
+ ellipse(360,886,19,19,1.3,.5,80);
383
+ line(341,886,379,886,1,.34,81);
384
+ line(360,867,360,905,1,.34,82);
385
+ poly([[39,526],[51,510],[66,526],[51,542]], true, 1.2,.47,90);
386
+ ellipse(418,745,9,9,1.1,.5,91);
387
+ line(418,754,418,779,1.2,.48,92);
388
+ line(405,766,431,766,1.2,.48,93);
389
+ poly([[151,278],[166,265],[183,273],[181,293],[160,299],[148,288]], true, 1.1,.45,94);
390
+ line(55,214,85,214,1.2,.42,95);
391
+ line(70,199,70,229,1.2,.42,96);
392
+ ellipse(69,214,22,22,1.1,.38,97);
393
+ }
394
+
395
+ function lensPath() {
396
+ g.beginPath();
397
+ g.moveTo(501, 242);
398
+ g.bezierCurveTo(552, 335, 551, 676, 501, 785);
399
+ g.bezierCurveTo(451, 682, 450, 340, 501, 242);
400
+ g.closePath();
401
+ }
402
+
403
+ function drawLens() {
404
+ lensPath();
405
+ g.fillStyle = "rgba(231,226,215,.82)";
406
+ g.fill();
407
+ g.save();
408
+ lensPath();
409
+ g.clip();
410
+ g.beginPath();
411
+ for (let x = 452; x < 550; x += 9) {
412
+ g.moveTo(x, 210);
413
+ g.lineTo(x - 84, 830);
414
+ }
415
+ g.strokeStyle = "rgba(39,40,35,.17)";
416
+ g.lineWidth = .8;
417
+ g.stroke();
418
+ g.restore();
419
+ pencil(lensPath, 2.3, .82, 4, 301);
420
+ pencil(() => {
421
+ g.beginPath();
422
+ g.moveTo(494,252);
423
+ g.bezierCurveTo(468,382,469,647,494,775);
424
+ }, .8, .35, 2, 302);
425
+ }
426
+
427
+ function drawRays() {
428
+ const rays = [
429
+ [512,395,760,285],
430
+ [520,440,790,380],
431
+ [523,492,756,492],
432
+ [521,545,792,612],
433
+ [512,594,756,742]
434
+ ];
435
+ rays.forEach((ray, i) => arrow(...ray, 410 + i, .55));
436
+ g.save();
437
+ g.setLineDash([2,8]);
438
+ g.strokeStyle = "rgba(39,40,35,.28)";
439
+ g.lineWidth = 1;
440
+ g.beginPath();
441
+ g.moveTo(510,348); g.lineTo(900,202);
442
+ g.moveTo(516,646); g.lineTo(920,840);
443
+ g.stroke();
444
+ g.restore();
445
+ }
446
+
447
+ function drawSunAndCloud() {
448
+ ellipse(925,203,42,42,1.8,.68,500);
449
+ for (let i = 0; i < 12; i++) {
450
+ const a = i / 12 * TAU;
451
+ line(925 + Math.cos(a)*55, 203 + Math.sin(a)*55,
452
+ 925 + Math.cos(a)*82, 203 + Math.sin(a)*82, 1.1,.45,510+i);
453
+ }
454
+ drawCloud(780,220,48,540);
455
+ }
456
+
457
+ function drawMountain() {
458
+ const bell = (u, v, cu, cv, su, sv, amplitude) => {
459
+ const du = (u - cu) / su;
460
+ const dv = (v - cv) / sv;
461
+ return amplitude * Math.exp(-(du * du + dv * dv));
462
+ };
463
+ const height = (u, v) => Math.max(-.1,
464
+ bell(u,v,.02,.18,.43,.34,1.02) +
465
+ bell(u,v,-.7,.42,.29,.31,.58) +
466
+ bell(u,v,.69,.39,.3,.3,.66) -
467
+ bell(u,v,.02,.78,.42,.2,.2)
468
+ );
469
+ const project = (u, v, elevation) => ({
470
+ x: 895 + u * (176 + v * 78),
471
+ y: 326 + v * 182 - elevation * 154,
472
+ depth: v
473
+ });
474
+
475
+ PencilLight.meshSurface({
476
+ height,
477
+ project,
478
+ columns: 17,
479
+ rows: 12,
480
+ samples: 62,
481
+ seed: 600
482
+ });
483
+
484
+ const road = [
485
+ ...PencilLight.cubic(
486
+ {x:930,y:220},{x:858,y:264},{x:966,y:303},{x:890,y:345},18
487
+ ).slice(0,-1),
488
+ ...PencilLight.cubic(
489
+ {x:890,y:345},{x:808,y:382},{x:937,y:411},{x:831,y:455},20
490
+ ).slice(0,-1),
491
+ ...PencilLight.cubic(
492
+ {x:831,y:455},{x:762,y:483},{x:831,y:511},{x:758,y:544},18
493
+ )
494
+ ];
495
+ road.forEach((point, i) => point.depth = i / (road.length - 1));
496
+ PencilLight.ribbon(road, depth => 8 + Math.pow(depth, 1.7) * 28, { seed: 710 });
497
+ }
498
+
499
+ function drawBars(x,y) {
500
+ line(x-12,y+61,x+102,y+61,1.5,.55,800);
501
+ line(x-12,y+61,x-12,y-10,1.5,.55,801);
502
+ const heights=[21,40,69,52,88];
503
+ heights.forEach((h,i)=>{
504
+ const bx=x+i*21;
505
+ poly([[bx,y+60],[bx,y+60-h],[bx+13,y+60-h],[bx+13,y+60]],false,1.2,.5,810+i);
506
+ for(let yy=y+56;yy>y+60-h;yy-=7) line(bx+2,yy,bx+11,yy,0.7,.22,830+i+yy);
507
+ });
508
+ }
509
+
510
+ function drawNetwork(x,y) {
511
+ const nodes=[[0,0],[55,-28],[95,18],[74,70],[20,82],[-22,42],[42,32]];
512
+ const edges=[[0,1],[1,2],[2,3],[3,4],[4,5],[5,0],[0,6],[1,6],[2,6],[3,6],[4,6]];
513
+ edges.forEach((e,i)=>line(x+nodes[e[0]][0],y+nodes[e[0]][1],x+nodes[e[1]][0],y+nodes[e[1]][1],1.1,.45,900+i));
514
+ nodes.forEach((n,i)=>ellipse(x+n[0],y+n[1],7,7,1.4,.6,930+i));
515
+ }
516
+
517
+ function drawGlobe(x,y,r) {
518
+ ellipse(x,y,r,r,1.7,.62,950);
519
+ pencil(()=>{g.beginPath();g.ellipse(x,y,r*.46,r,0,0,TAU);},1,.42,2,951);
520
+ pencil(()=>{g.beginPath();g.ellipse(x,y,r,r*.42,0,0,TAU);},1,.42,2,952);
521
+ pencil(()=>{
522
+ g.beginPath();
523
+ g.moveTo(x-r*.72,y-r*.18);
524
+ g.bezierCurveTo(x-r*.25,y-r*.52,x-r*.08,y-r*.18,x+r*.12,y-r*.35);
525
+ g.bezierCurveTo(x+r*.32,y-r*.51,x+r*.5,y-r*.12,x+r*.72,y-r*.1);
526
+ g.moveTo(x-r*.58,y+r*.15);
527
+ g.bezierCurveTo(x-r*.28,y+r*.02,x-r*.18,y+r*.5,x+r*.18,y+r*.28);
528
+ g.bezierCurveTo(x+r*.36,y+r*.14,x+r*.55,y+r*.44,x+r*.66,y+r*.22);
529
+ },1.2,.5,2,953);
530
+ }
531
+
532
+ function drawPlant(x,y) {
533
+ line(x,y+80,x,y,1.8,.58,1000);
534
+ pencil(()=>{g.beginPath();g.moveTo(x,y+47);g.bezierCurveTo(x-48,y+24,x-50,y-9,x-6,y+17);g.bezierCurveTo(x+6,y+26,x+3,y+39,x,y+47);},1.5,.54,2,1001);
535
+ pencil(()=>{g.beginPath();g.moveTo(x,y+58);g.bezierCurveTo(x+48,y+35,x+53,y+4,x+7,y+29);g.bezierCurveTo(x-1,y+38,x-2,y+49,x,y+58);},1.5,.54,2,1002);
536
+ line(x-38,y+82,x+39,y+82,1.2,.42,1003);
537
+ }
538
+
539
+ function drawPeople(x,y) {
540
+ const people=[[-38,3,20],[0,-7,24],[41,4,19]];
541
+ people.forEach((p,i)=>{
542
+ ellipse(x+p[0],y+p[1]-p[2]*1.8,p[2]*.36,p[2]*.36,1.4,.55,1050+i);
543
+ pencil(()=>{
544
+ g.beginPath();
545
+ g.moveTo(x+p[0],y+p[1]-p[2]*1.35);
546
+ g.lineTo(x+p[0],y+p[1]+p[2]*.45);
547
+ g.moveTo(x+p[0]-p[2]*.65,y+p[1]-p[2]*.48);
548
+ g.lineTo(x+p[0]+p[2]*.65,y+p[1]-p[2]*.48);
549
+ g.moveTo(x+p[0],y+p[1]+p[2]*.45);
550
+ g.lineTo(x+p[0]-p[2]*.42,y+p[1]+p[2]*1.25);
551
+ g.moveTo(x+p[0],y+p[1]+p[2]*.45);
552
+ g.lineTo(x+p[0]+p[2]*.42,y+p[1]+p[2]*1.25);
553
+ },1.4,.55,2,1060+i);
554
+ });
555
+ }
556
+
557
+ function drawRightSymbols() {
558
+ drawBars(1062,554);
559
+ drawNetwork(835,670);
560
+ drawGlobe(1050,760,60);
561
+ drawPlant(748,865);
562
+ drawPeople(925,915);
563
+ ellipse(1114,890,9,9,1.2,.44,1100);
564
+ poly([[1110,899],[1120,925],[1104,925]],false,1.1,.4,1101);
565
+ }
566
+
567
+ function render() {
568
+ drawPaper();
569
+ dottedJourney();
570
+ drawChaos();
571
+ drawDoodles();
572
+ drawSunAndCloud();
573
+ drawRays();
574
+ drawMountain();
575
+ drawRightSymbols();
576
+ drawLens();
577
+ }
578
+
579
+ render();
580
+ </script>
581
+ </body>
582
+ </html>