@echomem/mcp 1.4.9 → 1.4.10
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/assets/hud/github.svg +1 -0
- package/dist/city/README.md +9 -0
- package/dist/city/echo-ai-city-only.html +54 -93
- package/dist/context-analysis/claude-canonical-adapter.js +315 -0
- package/dist/context-analysis/claude-native-canonical.js +35 -12
- package/dist/context-metrics/calculate.js +2 -15
- package/dist/context-metrics/estimator.js +45 -0
- package/dist/context-metrics/ledger.js +507 -0
- package/dist/context-metrics/parse-claude.js +227 -0
- package/dist/context-metrics/parse-codex.js +276 -0
- package/dist/hud/adapters.js +69 -198
- package/dist/hud/cli.js +0 -0
- package/dist/hud/efficiency.js +447 -0
- package/dist/hud/electron-main.js +3 -2
- package/dist/hud/fs.js +14 -0
- package/dist/hud/metric.js +4 -98
- package/dist/hud/monitor.js +1 -12
- package/dist/hud/render.js +4 -3
- package/dist/hud/server.js +30 -0
- package/dist/hud/web.js +409 -186
- package/dist/index.js +0 -0
- package/dist/setup-page/client-core.js +475 -0
- package/dist/setup-page/client-extraction.js +550 -0
- package/dist/setup-page/client-lifecycle.js +116 -0
- package/dist/setup-page/client-report-audit.js +818 -0
- package/dist/setup-page/client-report-city.js +204 -0
- package/dist/setup-page/client-report.js +6 -0
- package/dist/setup-page/client.js +15 -0
- package/dist/setup-page/document.js +37 -0
- package/dist/setup-page/styles-city-report.js +880 -0
- package/dist/setup-page/styles-context-audit.js +470 -0
- package/dist/setup-page/styles-extraction.js +821 -0
- package/dist/setup-page/styles-foundation.js +231 -0
- package/dist/setup-page/styles.js +11 -0
- package/dist/setup-page.js +6 -5623
- package/dist/setup.js +24 -10
- package/package.json +4 -4
- package/dist/city/10-problems-report.html +0 -649
- package/dist/city/_live.html +0 -37
- package/dist/city/_serve.mjs +0 -45
- package/dist/city/card-data.json +0 -15
- package/dist/city/chaos-to-clarity-pencil.html +0 -582
- package/dist/city/city-data.json +0 -248
- package/dist/city/echo-ai-city-only.template.html +0 -2271
- package/dist/city/generate-echo-city-only.mjs +0 -112
- package/dist/city/pencil-pie-generator.html +0 -883
- package/dist/city/pencil-webgl-landscape.html +0 -1239
- package/dist/city/spatial-fan-story.html +0 -479
package/dist/city/_serve.mjs
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import http from "node:http";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
|
|
5
|
-
const root = path.resolve("artifacts");
|
|
6
|
-
const PORT = 8787;
|
|
7
|
-
const types = {
|
|
8
|
-
".html": "text/html; charset=utf-8",
|
|
9
|
-
".png": "image/png",
|
|
10
|
-
".json": "application/json",
|
|
11
|
-
".css": "text/css",
|
|
12
|
-
".js": "text/javascript",
|
|
13
|
-
".svg": "image/svg+xml",
|
|
14
|
-
".wasm": "application/wasm",
|
|
15
|
-
".riv": "application/octet-stream",
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
http
|
|
19
|
-
.createServer((req, res) => {
|
|
20
|
-
let p = decodeURIComponent(req.url.split("?")[0]);
|
|
21
|
-
if (p === "/") p = "/_live.html";
|
|
22
|
-
const f = path.join(root, p);
|
|
23
|
-
if (!f.startsWith(root)) {
|
|
24
|
-
res.writeHead(403);
|
|
25
|
-
return res.end();
|
|
26
|
-
}
|
|
27
|
-
fs.stat(f, (err, st) => {
|
|
28
|
-
if (err || !st.isFile()) {
|
|
29
|
-
res.writeHead(404);
|
|
30
|
-
return res.end("not found");
|
|
31
|
-
}
|
|
32
|
-
const headers = {
|
|
33
|
-
"Last-Modified": st.mtime.toUTCString(),
|
|
34
|
-
"Cache-Control": "no-store",
|
|
35
|
-
};
|
|
36
|
-
if (req.method === "HEAD") {
|
|
37
|
-
res.writeHead(200, headers);
|
|
38
|
-
return res.end();
|
|
39
|
-
}
|
|
40
|
-
headers["Content-Type"] = types[path.extname(f)] || "application/octet-stream";
|
|
41
|
-
res.writeHead(200, headers);
|
|
42
|
-
fs.createReadStream(f).pipe(res);
|
|
43
|
-
});
|
|
44
|
-
})
|
|
45
|
-
.listen(PORT, () => console.log(`serving ${root} on http://localhost:${PORT}`));
|
package/dist/city/card-data.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_note": "Frozen snapshot for the Repo City share card (Kobe). Only the keys generate-echo-city-only.mjs actually renders remain — dead fields were pruned in the Carmack cleanup. For multi-user / the setup flow these must be DERIVED from buildForensicReport(), not frozen — see docs/repo-city-setup-integration-plan.md.",
|
|
3
|
-
"computeCost": "$13,689",
|
|
4
|
-
"attentionHours": 191.1,
|
|
5
|
-
"split": { "codexPct": 26, "claudePct": 74 },
|
|
6
|
-
"dirty": { "pct": "85.0" },
|
|
7
|
-
"persona": {
|
|
8
|
-
"primary": "bossy",
|
|
9
|
-
"rank": "the architect",
|
|
10
|
-
"rhythm": "marathoner",
|
|
11
|
-
"sides": ["loopy", "lusty", "maxxy"],
|
|
12
|
-
"verdict": "you don't write code, you run a daycare for <b>163</b> sleepless interns who reread the same file into amnesia and bill every typo to Opus — <b>$13,689</b> later, you wanted a helper and became a dad. 🗿"
|
|
13
|
-
},
|
|
14
|
-
"counterfactual": { "reachDate": "Jun 2", "insteadOf": "Jun 20", "daysEarlier": 18 }
|
|
15
|
-
}
|
|
@@ -1,582 +0,0 @@
|
|
|
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>
|