@zerwiz/ymir 0.1.16 → 0.1.18
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/.agents/config/app-repos.yaml +38 -0
- package/.claude/settings.json +31 -0
- package/.codex/hooks.json +43 -0
- package/.cursor/hooks.json +33 -0
- package/.pi/extensions/README.md +39 -0
- package/.pi/extensions/gna-pi-watch.ts +15 -0
- package/.pi/extensions/lib/ro-assistant-layout.ts +96 -0
- package/.pi/extensions/lib/ro-operational-user-layout.ts +145 -0
- package/.pi/extensions/lib/ro-visibility.ts +99 -0
- package/.pi/extensions/lib/ro-working-ship.ts +243 -0
- package/.pi/extensions/lib/rodd-operational-input.ts +62 -0
- package/.pi/extensions/lib/skuld-branch-dispatch.ts +252 -0
- package/.pi/extensions/lib/skuld-branch-model-picker.ts +77 -0
- package/.pi/extensions/lib/vordr-sessionstart-supervisor.mjs +48 -0
- package/.pi/extensions/ro.ts +11 -0
- package/.pi/extensions/skuld-branch-supervision.ts +11 -0
- package/.pi/extensions/syn-turnend-guard.ts +11 -0
- package/.pi/mcp.json +16 -0
- package/.pi/mcp.json.example +11 -0
- package/.pi/npm/.gitignore +2 -0
- package/.pi/settings.json +8 -0
- package/.pi/shared/extensions/gna-pi-watch.ts +750 -0
- package/.pi/shared/extensions/herdr-agent-state.ts +257 -0
- package/.pi/shared/extensions/open-editor.ts +509 -0
- package/.pi/shared/extensions/ro.ts +504 -0
- package/.pi/shared/extensions/skuld-branch-supervision.ts +1535 -0
- package/.pi/shared/extensions/syn-turnend-guard.ts +683 -0
- package/.pi/shared/extensions/todo.ts +133 -0
- package/.pi/shared/extensions/ymir-subagents.ts +287 -0
- package/.pi/shared/extensions/ymir-well.ts +130 -0
- package/CHANGELOG.md +23 -0
- package/assets/Ymir.md +4654 -0
- package/assets/healer.html +717 -0
- package/assets/icon-family/family-sheet.png +0 -0
- package/assets/icon-family/hlidskjalf.svg +1 -0
- package/assets/icon-family/sessrumnir.svg +1 -0
- package/assets/icon-family/smidja.svg +1 -0
- package/assets/icon-family/ymir.svg +1 -0
- package/assets/mimirswell.html +880 -0
- package/assets/mock/README.md +16 -0
- package/assets/mock/feeds.ts +175 -0
- package/assets/mock/mock.ts +408 -0
- package/assets/reference/docs/agent-control.md +122 -0
- package/assets/reference/docs/apodex/Appdex_as_Orchestrator_Planner_Reviewer_Assessment.md +176 -0
- package/assets/reference/docs/apodex/Final Report(1).md +198 -0
- package/assets/reference/docs/apodex/Final Report(2).md +54 -0
- package/assets/reference/docs/apodex/Final Report(3).md +40 -0
- package/assets/reference/docs/apodex/Final Report(4).md +234 -0
- package/assets/reference/docs/apodex/Final Report(5).md +13 -0
- package/assets/reference/docs/apodex/Final Report.md +82 -0
- package/assets/reference/docs/architecture.md +392 -0
- package/assets/reference/docs/arm-pretool-check.md +247 -0
- package/assets/reference/docs/calm-mode-feasibility.md +541 -0
- package/assets/reference/docs/calm.md +59 -0
- package/assets/reference/docs/captain-hold-lifecycle.md +96 -0
- package/assets/reference/docs/cd-guard.md +165 -0
- package/assets/reference/docs/cmux-backend.md +133 -0
- package/assets/reference/docs/codex-app-backend.md +57 -0
- package/assets/reference/docs/configuration.md +924 -0
- package/assets/reference/docs/documentation-audiences.json +468 -0
- package/assets/reference/docs/documentation-audiences.md +28 -0
- package/assets/reference/docs/examples/crew-dispatch.json +26 -0
- package/assets/reference/docs/examples/process-event-extension/file-signal.mjs +96 -0
- package/assets/reference/docs/examples/process-event-extension/firstmate-extension.json +15 -0
- package/assets/reference/docs/examples/watched-tools.json +24 -0
- package/assets/reference/docs/examples/wedge-alarm +22 -0
- package/assets/reference/docs/extension-bindings.md +237 -0
- package/assets/reference/docs/fm-test-isolation-proof.json +37 -0
- package/assets/reference/docs/fm-test-isolation-proof.md +149 -0
- package/assets/reference/docs/fm-test-portable-shards.md +118 -0
- package/assets/reference/docs/gitlab-merge-watch.md +275 -0
- package/assets/reference/docs/herdr-backend.md +346 -0
- package/assets/reference/docs/orca-backend.md +84 -0
- package/assets/reference/docs/pi-supervision-branch-poster.svg +125 -0
- package/assets/reference/docs/pi-supervision-branch.md +96 -0
- package/assets/reference/docs/plans/agentic-engineering-workflow.md +395 -0
- package/assets/reference/docs/plans/agentic-factory-implementation-plan.md +615 -0
- package/assets/reference/docs/plans/command-factory-enhancement-plan.md +420 -0
- package/assets/reference/docs/plans/phase-1-layer3-program-design.md +134 -0
- package/assets/reference/docs/plans/phase-2-vertical-slices.md +100 -0
- package/assets/reference/docs/plans/phase-3-measurable-goals.md +106 -0
- package/assets/reference/docs/plans/phase-4-context-budget.md +106 -0
- package/assets/reference/docs/plans/phase-5-pre-mortem-confidence.md +100 -0
- package/assets/reference/docs/plans/phase-6-incident-to-agent.md +109 -0
- package/assets/reference/docs/remote-secondmates.md +268 -0
- package/assets/reference/docs/scripts.md +146 -0
- package/assets/reference/docs/sessionstart-nudge.md +115 -0
- package/assets/reference/docs/subagent-guard.md +383 -0
- package/assets/reference/docs/supervision-protocols/claude.md +27 -0
- package/assets/reference/docs/supervision-protocols/codex.md +16 -0
- package/assets/reference/docs/supervision-protocols/cursor.md +31 -0
- package/assets/reference/docs/supervision-protocols/grok.md +39 -0
- package/assets/reference/docs/supervision-protocols/opencode.md +17 -0
- package/assets/reference/docs/supervision-protocols/pi.md +33 -0
- package/assets/reference/docs/supervision-protocols/unknown.md +13 -0
- package/assets/reference/docs/tmux-backend.md +115 -0
- package/assets/reference/docs/trace-context.md +117 -0
- package/assets/reference/docs/turnend-guard.md +170 -0
- package/assets/reference/docs/verification/dispatch-auth.md +204 -0
- package/assets/reference/docs/verification/muse.md +221 -0
- package/assets/reference/docs/verification/process-event-sources.md +208 -0
- package/assets/reference/docs/verification/public-followup.md +119 -0
- package/assets/reference/docs/verification/runtime-backends.md +1022 -0
- package/assets/reference/docs/verification/stow-memory.md +53 -0
- package/assets/reference/docs/verification/supervision.md +534 -0
- package/assets/reference/docs/verification/trace-context.md +31 -0
- package/assets/reference/docs/voice-relay.md +295 -0
- package/assets/reference/docs/watcher-continuity.md +119 -0
- package/assets/reference/docs/wedge-alarm.md +39 -0
- package/assets/reference/docs/zellij-backend.md +114 -0
- package/assets/reference/index.html +1172 -0
- package/assets/reference/skills/afk/SKILL.md +241 -0
- package/assets/reference/skills/ahoy/SKILL.md +56 -0
- package/assets/reference/skills/ask-user-authority/SKILL.md +56 -0
- package/assets/reference/skills/bearings/SKILL.md +161 -0
- package/assets/reference/skills/bearings/assets/board-template.html +731 -0
- package/assets/reference/skills/bootstrap-diagnostics/SKILL.md +68 -0
- package/assets/reference/skills/captain-hold-lifecycle/SKILL.md +54 -0
- package/assets/reference/skills/decision-hold-lifecycle/SKILL.md +15 -0
- package/assets/reference/skills/diagnostic-reasoning/SKILL.md +53 -0
- package/assets/reference/skills/firstmate-codexapp/SKILL.md +110 -0
- package/assets/reference/skills/firstmate-codexapp/agents/openai.yaml +4 -0
- package/assets/reference/skills/firstmate-coding-guidelines/SKILL.md +127 -0
- package/assets/reference/skills/firstmate-orca/SKILL.md +92 -0
- package/assets/reference/skills/fmx-respond/SKILL.md +283 -0
- package/assets/reference/skills/harness-adapters/SKILL.md +95 -0
- package/assets/reference/skills/harness-adapters/references/common/control-and-recovery.md +37 -0
- package/assets/reference/skills/harness-adapters/references/common/dispatch.md +32 -0
- package/assets/reference/skills/harness-adapters/references/common/model-and-effort.md +42 -0
- package/assets/reference/skills/harness-adapters/references/common/primary-hooks.md +40 -0
- package/assets/reference/skills/harness-adapters/references/harness/claude.md +55 -0
- package/assets/reference/skills/harness-adapters/references/harness/codex.md +43 -0
- package/assets/reference/skills/harness-adapters/references/harness/cursor.md +75 -0
- package/assets/reference/skills/harness-adapters/references/harness/grok.md +69 -0
- package/assets/reference/skills/harness-adapters/references/harness/kimi.md +51 -0
- package/assets/reference/skills/harness-adapters/references/harness/muse.md +70 -0
- package/assets/reference/skills/harness-adapters/references/harness/opencode.md +42 -0
- package/assets/reference/skills/harness-adapters/references/harness/pi.md +56 -0
- package/assets/reference/skills/process-event-sources/SKILL.md +137 -0
- package/assets/reference/skills/project-management/SKILL.md +92 -0
- package/assets/reference/skills/quota-array-dispatch/SKILL.md +131 -0
- package/assets/reference/skills/secondmate-provisioning/SKILL.md +254 -0
- package/assets/reference/skills/stow/SKILL.md +309 -0
- package/assets/reference/skills/stuck-crewmate-recovery/SKILL.md +54 -0
- package/assets/reference/skills/updatefirstmate/SKILL.md +64 -0
- package/assets/skills/README.md +5 -0
- package/assets/yggdrasil.html +649 -0
- package/assets/ymir-banner-01.png +0 -0
- package/assets/ymir-banner-02.png +0 -0
- package/assets/ymir-banner-03.png +0 -0
- package/assets/ymir-banner-04.png +0 -0
- package/assets/ymir-banner-05.png +0 -0
- package/assets/ymir-banner-06.png +0 -0
- package/assets/ymir-emblem-darksteel.svg +63 -0
- package/assets/ymir-emblem-forged.svg +55 -0
- package/assets/ymir-emblem-slate.svg +55 -0
- package/assets/ymir-mark-algiz-anvil.svg +9 -0
- package/assets/ymir-stave.svg +53 -0
- package/assets/ymir.html +563 -0
- package/bin/ymir-install.sh +6 -1
- package/data/learnings.md +33 -0
- package/data/local-models.md +34 -0
- package/data/operator.md +15 -0
- package/data/projects.md +28 -0
- package/data/realm.md +1 -0
- package/deploy/Containerfile +27 -0
- package/deploy/README.md +104 -0
- package/deploy/compose/compose.yaml +45 -0
- package/deploy/env.example +30 -0
- package/deploy/quadlet/ymir.container +57 -0
- package/package.json +10 -8
|
@@ -0,0 +1,717 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Ymir — The Renewal and the Healing</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Cormorant:ital,wght@0,500;600;1,500&family=Newsreader:ital,opsz,wght@0,6..72,300..500;1,6..72,300..500&family=IBM+Plex+Mono:wght@300;400;500&family=Noto+Sans+Runic&display=swap" rel="stylesheet">
|
|
10
|
+
<style>
|
|
11
|
+
/* ============ tokens — obsidian, bone, bronze, blood ============ */
|
|
12
|
+
:root{
|
|
13
|
+
--bg:#0e0c09; --panel:#151209; --panel3:#14100b;
|
|
14
|
+
--line:#2b241a; --line-soft:#221d14;
|
|
15
|
+
--bone:#cfc3a9; --bone-dim:#9a8f75; --bone-faint:#6b6250;
|
|
16
|
+
--steel:#96a0a8; --steel-dim:#5f686e;
|
|
17
|
+
--bronze:#c9973f; --bronze-deep:#7d5f2a;
|
|
18
|
+
--blood:#7c3a30; --blood-lit:#c2584a;
|
|
19
|
+
--disp:'Cormorant',serif; --serif:'Newsreader',Georgia,serif;
|
|
20
|
+
--mono:'IBM Plex Mono',monospace; --run:'Noto Sans Runic','Segoe UI Historic',serif;
|
|
21
|
+
}
|
|
22
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
23
|
+
body{background:var(--bg);color:var(--bone);font-family:var(--serif);
|
|
24
|
+
-webkit-font-smoothing:antialiased;overflow-x:hidden}
|
|
25
|
+
::selection{background:#57411a;color:#f0e6cd}
|
|
26
|
+
:focus-visible{outline:1px solid var(--bronze);outline-offset:3px}
|
|
27
|
+
.rn{font-family:var(--run)}
|
|
28
|
+
|
|
29
|
+
/* stone grain + vignette */
|
|
30
|
+
body::before{content:'';position:fixed;inset:0;z-index:60;pointer-events:none;opacity:.055;
|
|
31
|
+
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
|
|
32
|
+
body::after{content:'';position:fixed;inset:0;z-index:59;pointer-events:none;
|
|
33
|
+
box-shadow:inset 0 0 170px 30px rgba(0,0,0,.5)}
|
|
34
|
+
#gap{position:fixed;inset:0;width:100%;height:100%;z-index:0}
|
|
35
|
+
main,footer{position:relative;z-index:2}
|
|
36
|
+
|
|
37
|
+
/* ============ topbar ============ */
|
|
38
|
+
.topbar{position:fixed;inset:0 0 auto 0;height:46px;display:flex;justify-content:space-between;align-items:center;
|
|
39
|
+
padding:0 clamp(1rem,3vw,2rem);z-index:50;background:rgba(13,11,8,.78);backdrop-filter:blur(10px);
|
|
40
|
+
border-bottom:1px solid var(--line-soft);font-family:var(--mono);font-size:.58rem;
|
|
41
|
+
letter-spacing:.3em;color:var(--bone-dim);text-transform:uppercase}
|
|
42
|
+
.topbar .rn{color:var(--bronze);margin-right:.6em;font-size:.85rem}
|
|
43
|
+
main{padding-top:46px}
|
|
44
|
+
@keyframes fadeUp{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
|
|
45
|
+
|
|
46
|
+
/* ============ lore head ============ */
|
|
47
|
+
.lore-head{padding:5.5rem 1.5rem 0;text-align:center}
|
|
48
|
+
.lh-k{font-family:var(--mono);font-size:.58rem;letter-spacing:.44em;text-indent:.44em;color:var(--steel-dim);
|
|
49
|
+
text-transform:uppercase;animation:fadeUp 1s .05s both}
|
|
50
|
+
.lore-head h1{font-family:var(--disp);font-weight:600;font-size:clamp(1.9rem,5.4vw,3.4rem);
|
|
51
|
+
letter-spacing:.16em;text-indent:.16em;color:var(--bone);margin-top:1.3rem;
|
|
52
|
+
text-shadow:0 -1px 0 rgba(0,0,0,.85);animation:fadeUp 1s .18s both}
|
|
53
|
+
.lh-motto{font-family:var(--mono);font-size:.6rem;letter-spacing:.34em;text-indent:.34em;color:var(--bronze);
|
|
54
|
+
text-transform:uppercase;margin-top:1.2rem;animation:fadeUp 1s .32s both}
|
|
55
|
+
.lh-rule{width:150px;height:1px;background:var(--bronze-deep);margin:2.1rem auto 2.3rem;position:relative;
|
|
56
|
+
animation:fadeUp 1s .42s both}
|
|
57
|
+
.lh-rule::after{content:'';position:absolute;left:50%;top:50%;width:5px;height:5px;background:var(--bronze-deep);
|
|
58
|
+
transform:translate(-50%,-50%) rotate(45deg)}
|
|
59
|
+
.lh-body{max-width:62ch;margin:0 auto;font-size:1.04rem;line-height:1.95;color:var(--bone-dim);
|
|
60
|
+
animation:fadeUp 1s .52s both}
|
|
61
|
+
.lh-close{font-family:var(--disp);font-style:italic;font-size:clamp(1.05rem,2.2vw,1.3rem);letter-spacing:.06em;
|
|
62
|
+
color:var(--bone);margin:1.8rem auto 0;max-width:52ch;line-height:1.7;animation:fadeUp 1s .66s both}
|
|
63
|
+
|
|
64
|
+
/* ============ stage ============ */
|
|
65
|
+
.stage{position:relative;display:flex;align-items:center;justify-content:center;
|
|
66
|
+
padding:3.6rem 1rem 1.6rem;animation:fadeUp 1.1s .8s both}
|
|
67
|
+
.scenewrap{width:min(94vw, calc(74svh * .691), 600px);aspect-ratio:760/1100}
|
|
68
|
+
#scene{width:100%;height:100%;display:block}
|
|
69
|
+
.anno{position:absolute;top:110px;max-width:250px;line-height:1.95;font-size:.92rem;z-index:3}
|
|
70
|
+
.anno-l{left:clamp(1rem,4vw,3.2rem);font-style:italic;color:var(--bone-faint)}
|
|
71
|
+
.anno-r{right:clamp(1rem,4vw,3.2rem);text-align:right;font-family:var(--mono);font-size:.56rem;
|
|
72
|
+
letter-spacing:.26em;color:var(--steel-dim);text-transform:uppercase;line-height:2.6}
|
|
73
|
+
@media(max-width:900px){.anno{display:none}}
|
|
74
|
+
|
|
75
|
+
/* ============ SVG — the night carving ============ */
|
|
76
|
+
#scene text{font-family:var(--mono);user-select:none}
|
|
77
|
+
#scene g[data-part]{cursor:pointer;outline:none}
|
|
78
|
+
.wgroup{transition:opacity .45s}
|
|
79
|
+
#scene.focus g.wgroup:not(.lit){opacity:.45}
|
|
80
|
+
#treeG{transition:opacity .45s}
|
|
81
|
+
#scene.focus #treeG{opacity:.76}
|
|
82
|
+
|
|
83
|
+
/* tree anatomy (the myth side) */
|
|
84
|
+
.bpart .gs{stroke:#4a3d2a;fill:#161009;stroke-width:2;transition:stroke .4s,fill .4s}
|
|
85
|
+
.bpart .limb-o{fill:none;stroke:#4a3d2a;stroke-linecap:round;transition:stroke .4s}
|
|
86
|
+
.bpart .limb-i{fill:none;stroke:#0e0c09;stroke-linecap:round}
|
|
87
|
+
.bpart .det{fill:none;stroke:#2e261a;stroke-linecap:round;transition:stroke .4s}
|
|
88
|
+
.bpart .rid{fill:none;stroke:#4a4232;stroke-width:2.5}
|
|
89
|
+
.bpart.lit .gs{stroke:var(--bronze)}
|
|
90
|
+
.bpart.lit .fillable{fill:#241b0e}
|
|
91
|
+
.bpart.lit .limb-o{stroke:var(--bronze)}
|
|
92
|
+
.bpart.lit .det{stroke:var(--bronze)}
|
|
93
|
+
.bpart.lit .lab{fill:var(--bone)}
|
|
94
|
+
.bpart.lit .lab3{fill:var(--bone-dim)}
|
|
95
|
+
|
|
96
|
+
/* road (the machine side) */
|
|
97
|
+
.wgroup .gs{stroke:#4a4232;fill:#12100b;stroke-width:2;transition:stroke .4s,fill .4s}
|
|
98
|
+
.wgroup.lit .gs{stroke:var(--bronze)}
|
|
99
|
+
.mk{fill:#12100b;stroke:#4a4232;stroke-width:1.5;transition:stroke .5s,fill .5s}
|
|
100
|
+
.wgroup.lit .mk{stroke:var(--bronze);fill:#1a140c}
|
|
101
|
+
.mrune{font-family:var(--run);fill:#6b5b3a;transition:fill .5s}
|
|
102
|
+
.wgroup.lit .mrune{fill:var(--bronze)}
|
|
103
|
+
.rdash{fill:none;stroke:#2e261a;stroke-width:2.5;stroke-dasharray:16 12;transition:stroke .4s}
|
|
104
|
+
.wgroup.lit .rdash{stroke:var(--bronze);animation:march 1.1s linear infinite}
|
|
105
|
+
.gate{fill:none;stroke:#4a4232;stroke-width:3;transition:stroke .4s}
|
|
106
|
+
.wgroup.lit .gate{stroke:var(--bronze)}
|
|
107
|
+
.star{fill:#4f4530;stroke:none;animation:tw 4.5s ease-in-out infinite}
|
|
108
|
+
.wgroup.lit .star{fill:var(--bronze)}
|
|
109
|
+
@keyframes tw{50%{opacity:.25}}
|
|
110
|
+
@keyframes march{to{stroke-dashoffset:-28}}
|
|
111
|
+
|
|
112
|
+
/* moon */
|
|
113
|
+
#moonG .moonSt{fill:#12100b;stroke:#4a4232;stroke-width:2;transition:stroke .4s}
|
|
114
|
+
#moonG.lit .moonSt{stroke:var(--bronze)}
|
|
115
|
+
#moonG .mstar{fill:#4f4530;transition:fill .4s}
|
|
116
|
+
#moonG.lit .mstar{fill:var(--bronze)}
|
|
117
|
+
|
|
118
|
+
/* labels */
|
|
119
|
+
.lab{font-size:18px;letter-spacing:4.2px;fill:#6f6650;opacity:.92;paint-order:stroke;
|
|
120
|
+
stroke:#0e0c09;stroke-width:5;stroke-linejoin:round;transition:fill .4s}
|
|
121
|
+
.lab3{font-size:10px;letter-spacing:3px;fill:#5a5240;transition:fill .4s}
|
|
122
|
+
.wgroup.lit .lab{fill:var(--bone)}
|
|
123
|
+
.wgroup.lit .lab3{fill:var(--bone-dim)}
|
|
124
|
+
|
|
125
|
+
/* the crack and the mending */
|
|
126
|
+
.crackE{fill:none;stroke:#4a3d2a;stroke-width:9;stroke-linejoin:miter}
|
|
127
|
+
.crack{fill:none;stroke:#060504;stroke-width:5.5;stroke-linejoin:miter}
|
|
128
|
+
.seamBase{fill:none;stroke:#57411a;stroke-width:2;opacity:.55;stroke-linejoin:round}
|
|
129
|
+
.seam{fill:none;stroke:var(--bronze);stroke-width:3;stroke-linejoin:round;
|
|
130
|
+
stroke-dasharray:380;stroke-dashoffset:380}
|
|
131
|
+
.seam.lit{animation:seamdraw 1.6s ease-out forwards}
|
|
132
|
+
@keyframes seamdraw{to{stroke-dashoffset:0}}
|
|
133
|
+
.msp{fill:#c9973f;opacity:0;transform-box:fill-box;transform-origin:center}
|
|
134
|
+
.msp.lit{animation:mspk 2.4s ease-in-out infinite}
|
|
135
|
+
@keyframes mspk{0%,100%{opacity:0;transform:scale(.5)}50%{opacity:.9;transform:scale(1)}}
|
|
136
|
+
|
|
137
|
+
/* the pulse that never rests */
|
|
138
|
+
.vein{fill:none;stroke:#3a2f1c;stroke-width:2.5}
|
|
139
|
+
.pdot{fill:none;stroke:#c9973f;stroke-width:4;stroke-linecap:round;stroke-dasharray:14 560;
|
|
140
|
+
animation:rise 5.2s linear infinite;opacity:.85}
|
|
141
|
+
.pdot.p2{animation-delay:-2.6s}
|
|
142
|
+
@keyframes rise{from{stroke-dashoffset:574}to{stroke-dashoffset:0}}
|
|
143
|
+
.ptick{fill:#6d5426;opacity:.3;animation:tk 5.2s ease-in-out infinite}
|
|
144
|
+
@keyframes tk{0%,18%,100%{opacity:.22}9%{opacity:.95}}
|
|
145
|
+
#scene.healing .pdot{animation-duration:2.6s}
|
|
146
|
+
#scene.healing .pdot.p2{animation-delay:-1.3s}
|
|
147
|
+
#scene.healing .ptick{animation-duration:2.6s;fill:var(--bronze)}
|
|
148
|
+
|
|
149
|
+
/* new growth on the old wood */
|
|
150
|
+
.shoot{fill:#241d13;stroke:#3f3219;stroke-width:1;opacity:0;transform:scale(0);
|
|
151
|
+
transform-box:fill-box;transform-origin:50% 100%;transition:fill .4s}
|
|
152
|
+
.shoot.lit{fill:#6d5426;stroke:var(--bronze);animation:grow .55s cubic-bezier(.2,.7,.3,1.25) both}
|
|
153
|
+
@keyframes grow{from{opacity:0;transform:scale(0)}to{opacity:1;transform:scale(1)}}
|
|
154
|
+
.leaf2{fill:#2e261a;stroke:#3f3219;stroke-width:1;transition:fill .4s}
|
|
155
|
+
.bpart.lit .leaf2{fill:#8a6a34}
|
|
156
|
+
.bs{fill:none;stroke:#4a3d2a;stroke-width:2;transition:stroke .4s}
|
|
157
|
+
.bpart.lit .bs{stroke:var(--bronze)}
|
|
158
|
+
.patch{fill:#1a140d;stroke:#3f3219;stroke-width:1.2;transition:fill .4s,stroke .4s}
|
|
159
|
+
.patch.lit{fill:#2e2214;stroke:var(--bronze)}
|
|
160
|
+
|
|
161
|
+
/* the lantern */
|
|
162
|
+
.lgow{}
|
|
163
|
+
.lg1{fill:#c98a3f;animation:glowA 3.8s ease-in-out infinite}
|
|
164
|
+
.lg2{fill:#e8b45c;animation:glowB 3.8s ease-in-out infinite}
|
|
165
|
+
@keyframes glowA{0%,100%{opacity:.05}50%{opacity:.11}}
|
|
166
|
+
@keyframes glowB{0%,100%{opacity:.09}50%{opacity:.17}}
|
|
167
|
+
#scene.healing .lg1,#scene.healing .lg2{animation-duration:1.9s}
|
|
168
|
+
.lflame{animation:flick 2.6s ease-in-out infinite}
|
|
169
|
+
@keyframes flick{0%,100%{opacity:.65}50%{opacity:1}}
|
|
170
|
+
.lpost{fill:none;stroke:#4a3d2a;stroke-width:2.5}
|
|
171
|
+
|
|
172
|
+
/* connectors */
|
|
173
|
+
.lnk{fill:none;stroke:var(--bronze);stroke-width:1.6;stroke-dasharray:3 8;opacity:0;
|
|
174
|
+
transition:opacity .4s;pointer-events:none}
|
|
175
|
+
.lnk.lit{opacity:.75;animation:march 1.1s linear infinite}
|
|
176
|
+
|
|
177
|
+
/* hit areas */
|
|
178
|
+
.hit{fill:#000;fill-opacity:0;stroke:#000;stroke-opacity:0;pointer-events:all}
|
|
179
|
+
|
|
180
|
+
/* ============ caption + plinth ============ */
|
|
181
|
+
.plate{max-width:780px;margin:0 auto;padding:0 1.4rem 3rem}
|
|
182
|
+
.cap-hint{text-align:center;font-family:var(--mono);font-size:.58rem;letter-spacing:.18em;
|
|
183
|
+
color:var(--bone-faint);text-transform:uppercase;line-height:2.3;margin-bottom:.7rem}
|
|
184
|
+
.cap-hint b{color:var(--bronze);font-weight:400}
|
|
185
|
+
.cap{text-align:center;font-family:var(--mono);font-size:.62rem;letter-spacing:.24em;
|
|
186
|
+
text-transform:uppercase;color:var(--bone-faint);line-height:2.6}
|
|
187
|
+
.cap button{background:none;border:none;cursor:pointer;font:inherit;color:var(--bone-dim);
|
|
188
|
+
letter-spacing:inherit;padding:.2em .1em;border-bottom:1px solid transparent;
|
|
189
|
+
transition:color .25s,border-color .25s}
|
|
190
|
+
.cap button:hover,.cap button.on{color:var(--bronze);border-bottom-color:var(--bronze-deep)}
|
|
191
|
+
.cap button .rn{color:var(--bronze);margin-right:.45em}
|
|
192
|
+
.cap i{font-style:normal;color:var(--bone-faint);margin:0 .3em}
|
|
193
|
+
|
|
194
|
+
.carved{background:var(--panel3);border:1px solid var(--line);
|
|
195
|
+
box-shadow:inset 0 1px 0 rgba(255,244,214,.03),inset 0 -1px 0 rgba(0,0,0,.5),0 2px 16px rgba(0,0,0,.35)}
|
|
196
|
+
.plinth{margin-top:1.7rem;padding:1.7rem clamp(1.2rem,4vw,2.1rem) 1.9rem}
|
|
197
|
+
.pl-head{display:flex;align-items:center;gap:1.3rem;padding-bottom:1.2rem;border-bottom:1px solid var(--line)}
|
|
198
|
+
#pRune{font-family:var(--run);font-size:2.4rem;color:var(--bronze);line-height:1;letter-spacing:.08em}
|
|
199
|
+
.pl-k{font-family:var(--mono);font-size:.56rem;letter-spacing:.34em;color:var(--steel-dim);text-transform:uppercase}
|
|
200
|
+
#pName{font-family:var(--disp);font-weight:600;font-size:1.3rem;letter-spacing:.14em;color:var(--bone);margin-top:.35rem}
|
|
201
|
+
.prow{display:grid;grid-template-columns:5.4rem 1fr;gap:1.2rem;padding:1.05rem 0;
|
|
202
|
+
border-bottom:1px dashed var(--line-soft)}
|
|
203
|
+
.prow:last-of-type{border-bottom:none}
|
|
204
|
+
.ptag{font-family:var(--mono);font-size:.56rem;letter-spacing:.26em;color:var(--bronze);
|
|
205
|
+
text-transform:uppercase;padding-top:.4rem}
|
|
206
|
+
.pmyth{font-family:var(--serif);font-style:italic;font-size:1.05rem;color:var(--bone);line-height:1.75}
|
|
207
|
+
.pymir{font-family:var(--mono);font-size:.72rem;color:var(--steel);line-height:1.85}
|
|
208
|
+
.pl-head,.prow{transition:opacity .18s}
|
|
209
|
+
.plinth.swap .pl-head,.plinth.swap .prow{opacity:.06}
|
|
210
|
+
@media(max-width:560px){.prow{grid-template-columns:1fr;gap:.3rem}.ptag{padding-top:0}}
|
|
211
|
+
|
|
212
|
+
.pl-actions{text-align:center;margin-top:1.9rem}
|
|
213
|
+
.btn-carv{font-family:var(--mono);font-size:.64rem;letter-spacing:.32em;text-indent:.32em;text-transform:uppercase;
|
|
214
|
+
color:var(--bone);background:var(--panel);border:1px solid var(--line);padding:.95rem 1.9rem;cursor:pointer;
|
|
215
|
+
box-shadow:inset 0 1px 0 rgba(255,244,214,.05),inset 0 -1px 0 rgba(0,0,0,.55),0 2px 10px rgba(0,0,0,.4);
|
|
216
|
+
transition:border-color .3s,color .3s,transform .1s}
|
|
217
|
+
.btn-carv .rn{color:var(--bronze);margin-right:.7em;font-size:.85rem;letter-spacing:0;text-indent:0}
|
|
218
|
+
.btn-carv:hover{border-color:var(--bronze-deep);color:#e6dcc2}
|
|
219
|
+
.btn-carv:active{transform:translateY(1px)}
|
|
220
|
+
.btn-carv.busy{opacity:.55;pointer-events:none}
|
|
221
|
+
|
|
222
|
+
/* ============ unfold + pull ============ */
|
|
223
|
+
details.unfold{margin-top:2.4rem;border:1px solid var(--line);background:var(--panel3)}
|
|
224
|
+
details.unfold summary{padding:1.05rem 1.3rem;font-family:var(--mono);font-size:.62rem;letter-spacing:.32em;
|
|
225
|
+
color:var(--bone-dim);cursor:pointer;list-style:none;display:flex;align-items:center;gap:1rem;
|
|
226
|
+
text-transform:uppercase;transition:color .3s}
|
|
227
|
+
details.unfold summary::-webkit-details-marker{display:none}
|
|
228
|
+
details.unfold summary:hover{color:var(--bone)}
|
|
229
|
+
details.unfold summary .rn{color:var(--bronze);font-size:.95rem}
|
|
230
|
+
.tend-grid{display:grid;grid-template-columns:1fr 1fr;gap:2.4rem;padding:1.2rem 1.4rem 0}
|
|
231
|
+
@media(max-width:640px){.tend-grid{grid-template-columns:1fr}}
|
|
232
|
+
.tg-k{font-family:var(--mono);font-size:.6rem;letter-spacing:.3em;color:var(--bone-dim);
|
|
233
|
+
text-transform:uppercase;margin-bottom:.9rem}
|
|
234
|
+
.tg-k .rn{color:var(--bronze);margin-right:.5em;font-size:.9rem}
|
|
235
|
+
.tend-grid ul{list-style:none}
|
|
236
|
+
.tend-grid li{font-family:var(--mono);font-size:.62rem;color:var(--steel);line-height:1.7;
|
|
237
|
+
padding:.45rem 0 .45rem 1.1rem;border-bottom:1px dashed var(--line-soft);position:relative}
|
|
238
|
+
.tend-grid li::before{content:'—';position:absolute;left:0;color:var(--bronze-deep)}
|
|
239
|
+
.tg-road{font-family:var(--mono);font-size:.62rem;color:var(--steel-dim);padding:1.3rem 1.4rem 1.6rem;line-height:1.9}
|
|
240
|
+
.tg-road .rn{color:var(--bronze);margin-right:.5em}
|
|
241
|
+
|
|
242
|
+
.pull{font-family:var(--disp);font-size:clamp(1.05rem,2vw,1.3rem);letter-spacing:.06em;line-height:1.8;
|
|
243
|
+
color:var(--bone);border-left:2px solid var(--bronze-deep);padding:.3rem 0 .3rem 1.6rem;
|
|
244
|
+
margin:3rem auto 0;max-width:56ch}
|
|
245
|
+
.pull small{display:block;font-family:var(--mono);font-size:.56rem;letter-spacing:.3em;
|
|
246
|
+
color:var(--steel-dim);margin-top:.9rem;text-transform:uppercase}
|
|
247
|
+
|
|
248
|
+
/* ============ footer ============ */
|
|
249
|
+
footer{border-top:1px solid var(--line);padding:3.6rem 1.5rem 4rem;text-align:center;animation:fadeUp 1s .5s both}
|
|
250
|
+
.frule{display:flex;align-items:center;gap:1.4rem;max-width:640px;margin:0 auto 2.8rem}
|
|
251
|
+
.frule::before,.frule::after{content:'';flex:1;height:1px;background:var(--line-soft)}
|
|
252
|
+
.frule span{font-family:var(--run);font-size:.7rem;letter-spacing:.42em;color:var(--bone-faint);white-space:nowrap}
|
|
253
|
+
.f-big{font-family:var(--disp);font-weight:600;font-size:clamp(1.15rem,2.6vw,1.65rem);
|
|
254
|
+
letter-spacing:.14em;color:var(--bone);text-shadow:0 -1px 0 rgba(0,0,0,.8)}
|
|
255
|
+
.f-mono{font-family:var(--mono);font-size:.56rem;letter-spacing:.3em;color:var(--steel-dim);
|
|
256
|
+
margin-top:1.7rem;text-transform:uppercase;line-height:2.3}
|
|
257
|
+
.f-repo{font-family:var(--mono);font-size:.58rem;color:var(--bone-faint);letter-spacing:.16em;margin-top:1.2rem}
|
|
258
|
+
|
|
259
|
+
@media (prefers-reduced-motion:reduce){
|
|
260
|
+
*,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important}
|
|
261
|
+
.seam{stroke-dashoffset:0}
|
|
262
|
+
.shoot{opacity:1;transform:scale(1)}
|
|
263
|
+
.msp{opacity:.7}
|
|
264
|
+
}
|
|
265
|
+
</style>
|
|
266
|
+
</head>
|
|
267
|
+
<body>
|
|
268
|
+
|
|
269
|
+
<div class="topbar">
|
|
270
|
+
<span><span class="rn">ᛒᚹ</span>THE RENEWAL AND THE HEALING</span>
|
|
271
|
+
<span>between the days</span>
|
|
272
|
+
</div>
|
|
273
|
+
|
|
274
|
+
<canvas id="gap" aria-hidden="true"></canvas>
|
|
275
|
+
|
|
276
|
+
<main>
|
|
277
|
+
<!-- ============ THE LORE ============ -->
|
|
278
|
+
<header class="lore-head">
|
|
279
|
+
<p class="lh-k">the lore · §xii · between the days</p>
|
|
280
|
+
<h1>The Renewal and the Healing</h1>
|
|
281
|
+
<p class="lh-motto">one keeps the tree young · the other keeps it standing</p>
|
|
282
|
+
<div class="lh-rule"></div>
|
|
283
|
+
<p class="lh-body">Because the work is long, two figures tend the tree between the days. The first is
|
|
284
|
+
the renewer — a wise-woman whose hands coax the old metal back to life, who carries the whole tree
|
|
285
|
+
forward to its newest shape without breaking a single branch, and who mends the road ahead while the
|
|
286
|
+
smiths sleep. The second is the healer — a gentle one who walks the halls at quiet hours, finds what
|
|
287
|
+
has cracked, and makes it whole again, asking nothing in return.</p>
|
|
288
|
+
<p class="lh-close">The one renews the tree; the other heals it. Both are needed, and neither hurries.</p>
|
|
289
|
+
</header>
|
|
290
|
+
|
|
291
|
+
<!-- ============ THE NIGHT CARVING ============ -->
|
|
292
|
+
<section class="stage">
|
|
293
|
+
<p class="anno anno-l">Two figures tend the tree between the days — the renewer with a hand on the
|
|
294
|
+
trunk, the healer kneeling at the crack. The lantern is lit; the smiths are asleep.</p>
|
|
295
|
+
<p class="anno anno-r">renewal without breakage<br>healing without asking<br>the road mended<br>while the smiths sleep</p>
|
|
296
|
+
|
|
297
|
+
<div class="scenewrap">
|
|
298
|
+
<svg id="scene" viewBox="0 0 760 1100" role="group" aria-label="The tree tended at night by the renewer and the healer, with the road running on from it">
|
|
299
|
+
<defs>
|
|
300
|
+
<radialGradient id="halo" cx="50%" cy="50%" r="50%">
|
|
301
|
+
<stop offset="0" stop-color="#1c160e" stop-opacity=".55"/>
|
|
302
|
+
<stop offset="1" stop-color="#1c160e" stop-opacity="0"/>
|
|
303
|
+
</radialGradient>
|
|
304
|
+
</defs>
|
|
305
|
+
<ellipse cx="380" cy="520" rx="330" ry="440" fill="url(#halo)" pointer-events="none"/>
|
|
306
|
+
|
|
307
|
+
<g id="skyStars"></g>
|
|
308
|
+
|
|
309
|
+
<!-- the moon, over the road's end -->
|
|
310
|
+
<g id="moonG" data-part="road" tabindex="0" role="button" aria-label="the moon over the road ahead">
|
|
311
|
+
<circle class="moonSt" cx="662" cy="138" r="42"/>
|
|
312
|
+
<circle cx="678" cy="128" r="34" fill="#0e0c09"/>
|
|
313
|
+
<path class="mstar" d="M688 114 L691 118 L688 122 L685 118 Z"/>
|
|
314
|
+
</g>
|
|
315
|
+
|
|
316
|
+
<!-- ======== THE TREE ======== -->
|
|
317
|
+
<g id="treeG" class="bpart">
|
|
318
|
+
<path class="gs fillable" d="M146 308 C112 272 124 226 162 216 C146 178 170 144 208 152
|
|
319
|
+
C218 112 260 98 290 124 C304 76 356 64 380 98 C404 62 456 72 462 112 C500 94 538 118 534 154
|
|
320
|
+
C574 158 594 198 570 230 C604 248 600 290 562 304 C580 332 546 352 514 336 C502 360 458 368 440 344
|
|
321
|
+
C416 368 368 368 352 342 C326 360 286 352 276 324 C240 342 202 332 196 304 C170 318 148 314 146 308 Z"/>
|
|
322
|
+
<path class="gs" style="fill:#100c07" d="M214 322 C200 294 218 264 252 264 C256 234 296 226 316 248
|
|
323
|
+
C334 218 380 220 392 250 C418 228 456 242 456 272 C490 274 504 306 482 328 C490 352 464 368 440 358
|
|
324
|
+
C424 376 384 380 370 360 C346 374 310 368 302 346 C274 354 244 346 238 324 C226 332 212 330 214 322 Z"/>
|
|
325
|
+
<path class="det" d="M244 236 C264 220 288 226 290 244 C290 258 274 262 268 252" stroke-width="2"/>
|
|
326
|
+
<path class="det" d="M470 186 C490 170 514 176 516 194 C516 208 500 212 494 202" stroke-width="2"/>
|
|
327
|
+
<path class="det" d="M336 138 C354 124 376 130 378 146 C378 160 362 164 356 152" stroke-width="2"/>
|
|
328
|
+
<g id="leafDust"></g>
|
|
329
|
+
|
|
330
|
+
<!-- the bare branch — the old wood, waiting -->
|
|
331
|
+
<path class="limb-o" style="stroke-width:8" d="M248 334 C226 344 204 356 186 372"/>
|
|
332
|
+
<path class="limb-i" style="stroke-width:4" d="M248 334 C226 344 204 356 186 372"/>
|
|
333
|
+
<path class="limb-o" style="stroke-width:5" d="M200 352 C190 340 182 334 172 330"/>
|
|
334
|
+
<path class="limb-i" style="stroke-width:2.5" d="M200 352 C190 340 182 334 172 330"/>
|
|
335
|
+
<path class="limb-o" style="stroke-width:4" d="M212 350 C210 362 212 372 218 380"/>
|
|
336
|
+
<path class="limb-i" style="stroke-width:2" d="M212 350 C210 362 212 372 218 380"/>
|
|
337
|
+
|
|
338
|
+
<!-- the trunk, with the crack -->
|
|
339
|
+
<path class="gs fillable" d="M342 336 C334 388 338 438 332 492 C327 544 336 596 331 648
|
|
340
|
+
C328 688 334 726 328 760 C326 776 318 786 304 796 L456 796 C442 786 434 776 432 760
|
|
341
|
+
C426 726 432 688 429 648 C424 596 433 544 428 492 C422 438 426 388 418 336
|
|
342
|
+
C394 326 366 326 342 336 Z"/>
|
|
343
|
+
<path class="det" d="M346 400 C342 480 344 560 340 660 C338 720 342 760 340 788" stroke-width="2"/>
|
|
344
|
+
<path class="crackE" d="M410 900 L402 862 L410 824 L398 786 L406 748 L394 712 L402 676 L392 640 L400 604 L392 566"/>
|
|
345
|
+
<path class="crack" d="M410 900 L402 862 L410 824 L398 786 L406 748 L394 712 L402 676 L392 640 L400 604 L392 566"/>
|
|
346
|
+
|
|
347
|
+
<!-- the roots -->
|
|
348
|
+
<path class="limb-o" style="stroke-width:17" d="M320 792 C258 812 192 842 142 890 C112 918 94 952 86 992"/>
|
|
349
|
+
<path class="limb-i" style="stroke-width:10" d="M320 792 C258 812 192 842 142 890 C112 918 94 952 86 992"/>
|
|
350
|
+
<path class="limb-o" style="stroke-width:14" d="M352 798 C332 842 314 890 304 936 C298 964 296 986 296 1004"/>
|
|
351
|
+
<path class="limb-i" style="stroke-width:8" d="M352 798 C332 842 314 890 304 936 C298 964 296 986 296 1004"/>
|
|
352
|
+
<path class="limb-o" style="stroke-width:13" d="M410 798 C428 842 444 886 456 924 C462 944 464 960 462 972"/>
|
|
353
|
+
<path class="limb-i" style="stroke-width:7.5" d="M410 798 C428 842 444 886 456 924 C462 944 464 960 462 972"/>
|
|
354
|
+
<path class="limb-o" style="stroke-width:9" d="M420 800 C452 826 478 854 494 882 C502 896 498 908 486 908"/>
|
|
355
|
+
<path class="limb-i" style="stroke-width:4.5" d="M420 800 C452 826 478 854 494 882 C502 896 498 908 486 908"/>
|
|
356
|
+
<path class="limb-o" style="stroke-width:17" d="M446 792 C508 812 560 846 588 892 C604 918 610 946 610 972"/>
|
|
357
|
+
<path class="limb-i" style="stroke-width:10" d="M446 792 C508 812 560 846 588 892 C604 918 610 946 610 972"/>
|
|
358
|
+
<path class="gs" d="M80 985 L87 993 L80 1001 L73 993 Z"/>
|
|
359
|
+
<path class="gs" d="M290 999 L297 1007 L290 1015 L283 1007 Z"/>
|
|
360
|
+
|
|
361
|
+
<!-- the ground -->
|
|
362
|
+
<path class="rid" d="M60 1006 L745 1006"/>
|
|
363
|
+
<path id="ridgeHatch" class="det" stroke-width="1.2" d=""/>
|
|
364
|
+
</g>
|
|
365
|
+
|
|
366
|
+
<!-- ======== THE ROAD AHEAD ======== -->
|
|
367
|
+
<g id="roadG" class="wgroup" data-part="road" tabindex="0" role="button"
|
|
368
|
+
aria-label="the road ahead — mended by the renewer, walked by the fleet">
|
|
369
|
+
<path class="gs" style="fill:#100d08;stroke:none" d="M540 1004 L748 1004 L692 838 L668 838 Z"/>
|
|
370
|
+
<path class="gs" style="fill:none" d="M540 1004 L668 838"/>
|
|
371
|
+
<path class="gs" style="fill:none" d="M748 1004 L692 838"/>
|
|
372
|
+
<path class="rdash" d="M644 1000 L680 844"/>
|
|
373
|
+
<path class="mk" style="transition-delay:0ms" d="M541 996 L555 996 L555 966 L548 960 L541 966 Z"/>
|
|
374
|
+
<text class="mrune" x="548" y="988" text-anchor="middle" font-size="11">ᚠ</text>
|
|
375
|
+
<path class="mk" style="transition-delay:.15s" d="M576.5 951 L587.5 951 L587.5 929 L582 924 L576.5 929 Z"/>
|
|
376
|
+
<text class="mrune" x="582" y="945" text-anchor="middle" font-size="9">ᚱ</text>
|
|
377
|
+
<path class="mk" style="transition-delay:.3s" d="M609.5 910 L618.5 910 L618.5 895 L614 891 L609.5 895 Z"/>
|
|
378
|
+
<text class="mrune" x="614" y="905" text-anchor="middle" font-size="8">ᛏ</text>
|
|
379
|
+
<path class="mk" style="transition-delay:.45s" d="M638.5 873 L645.5 873 L645.5 862 L642 858 L638.5 862 Z"/>
|
|
380
|
+
<text class="mrune" x="642" y="869" text-anchor="middle" font-size="7">ᛊ</text>
|
|
381
|
+
<path class="gate" d="M664 838 L664 806"/>
|
|
382
|
+
<path class="gate" d="M694 838 L694 806"/>
|
|
383
|
+
<path class="gate" d="M656 808 L702 808"/>
|
|
384
|
+
<path class="gate" d="M679 798 L684 803 L679 808 L674 803 Z"/>
|
|
385
|
+
<path class="star" style="animation-delay:-1.2s" d="M679 770 L682.5 774 L679 778 L675.5 774 Z"/>
|
|
386
|
+
<text class="lab" x="644" y="1078" text-anchor="middle">THE ROAD AHEAD</text>
|
|
387
|
+
<text class="lab3" x="644" y="1095" text-anchor="middle">rut steel waits</text>
|
|
388
|
+
<path class="hit" d="M534 1008 L748 1008 L704 828 L656 824 Z"/>
|
|
389
|
+
</g>
|
|
390
|
+
|
|
391
|
+
<!-- the mended patch of road — the renewer's night work -->
|
|
392
|
+
<path class="patch" data-part="renewer" pointer-events="none"
|
|
393
|
+
d="M598 986 C618 992 640 992 660 986 C640 996 618 996 598 986 Z"/>
|
|
394
|
+
|
|
395
|
+
<!-- ======== THE RENEWER ======== -->
|
|
396
|
+
<g id="renewerG" class="bpart" data-part="renewer" tabindex="0" role="button"
|
|
397
|
+
aria-label="the renewer — the wise-woman who carries the tree forward">
|
|
398
|
+
<text class="lab" x="252" y="662" text-anchor="middle">THE RENEWER</text>
|
|
399
|
+
<text class="lab3" x="252" y="680" text-anchor="middle">the carrying hand</text>
|
|
400
|
+
<path class="gs" style="fill:none;stroke-width:3.5" d="M202 815 C199 794 197 772 199 754"/>
|
|
401
|
+
<path class="gs" style="fill:none;stroke-width:2" d="M199 776 C195 768 190 763 185 760"/>
|
|
402
|
+
<path class="leaf2" d="M199 752 C194 746 196 738 204 738 C207 745 205 751 199 752 Z"/>
|
|
403
|
+
<path class="leaf2" d="M185 760 C179 755 179 747 186 746 C190 752 190 758 185 760 Z"/>
|
|
404
|
+
<path class="leaf2" d="M193 772 C188 766 190 758 197 758 C200 765 199 771 193 772 Z"/>
|
|
405
|
+
<path class="limb-o" style="stroke-width:15" d="M260 748 C288 744 306 740 322 736"/>
|
|
406
|
+
<path class="limb-i" style="stroke-width:8" d="M260 748 C288 744 306 740 322 736"/>
|
|
407
|
+
<path class="limb-o" style="stroke-width:14" d="M240 752 C226 776 214 796 204 812"/>
|
|
408
|
+
<path class="limb-i" style="stroke-width:7" d="M240 752 C226 776 214 796 204 812"/>
|
|
409
|
+
<circle class="gs" cx="325" cy="734" r="6.5"/>
|
|
410
|
+
<circle class="gs" cx="202" cy="815" r="6"/>
|
|
411
|
+
<path class="gs" d="M233 721 C229 700 239 688 251 688 C264 688 272 700 270 720 C266 706 260 700 251 699 C243 699 237 707 235 721 Z"/>
|
|
412
|
+
<path class="gs" style="fill:#100c07" d="M235 718 C229 748 227 778 231 806 L243 801 C239 773 239 745 241 720 Z"/>
|
|
413
|
+
<circle class="gs" cx="251" cy="715" r="14"/>
|
|
414
|
+
<circle cx="256" cy="712" r="1.4" fill="#7d5f2a"/>
|
|
415
|
+
<path class="gs fillable" d="M238 730 C234 760 234 790 236 820 L232 900 C230 940 228 970 224 993 L276 993
|
|
416
|
+
C272 970 270 940 268 900 L264 820 C266 790 266 760 262 730 C254 724 246 724 238 730 Z"/>
|
|
417
|
+
<path class="det" d="M244 762 C242 830 244 900 242 968" stroke-width="1.6"/>
|
|
418
|
+
<path class="det" d="M256 764 C258 830 256 900 258 966" stroke-width="1.6"/>
|
|
419
|
+
<path class="det" d="M228 980 C244 986 258 986 272 980" stroke-width="1.6"/>
|
|
420
|
+
<path class="gs" d="M250 996 L294 996 L298 1004 L288 1004 L286 1012 L258 1012 L256 1004 L246 1004 Z"/>
|
|
421
|
+
<path class="gs" d="M258 992 C266 983 282 983 288 991 L284 996 L262 996 Z"/>
|
|
422
|
+
<path class="bs" d="M273 984 L273 996"/>
|
|
423
|
+
<rect class="hit" x="166" y="636" width="188" height="384"/>
|
|
424
|
+
</g>
|
|
425
|
+
|
|
426
|
+
<!-- ======== THE HEALER ======== -->
|
|
427
|
+
<g id="healerG" class="bpart" data-part="healer" tabindex="0" role="button"
|
|
428
|
+
aria-label="the healer — the gentle one who mends what has cracked">
|
|
429
|
+
<text class="lab" x="494" y="810" text-anchor="middle">THE HEALER</text>
|
|
430
|
+
<text class="lab3" x="494" y="828" text-anchor="middle">the mending hand</text>
|
|
431
|
+
<path class="limb-o" style="stroke-width:11" d="M470 892 C456 902 444 912 436 920"/>
|
|
432
|
+
<path class="limb-i" style="stroke-width:5.5" d="M470 892 C456 902 444 912 436 920"/>
|
|
433
|
+
<path class="limb-o" style="stroke-width:11" d="M480 898 C466 908 454 918 446 926"/>
|
|
434
|
+
<path class="limb-i" style="stroke-width:5.5" d="M480 898 C466 908 454 918 446 926"/>
|
|
435
|
+
<circle class="gs" cx="434" cy="921" r="5"/>
|
|
436
|
+
<circle class="gs" cx="443" cy="927" r="5"/>
|
|
437
|
+
<path class="gs" d="M466 870 C460 894 464 918 476 934 C468 954 460 974 454 993 L534 995
|
|
438
|
+
C542 970 540 942 528 918 C536 900 536 882 528 868 C514 878 496 880 484 872 C478 876 470 876 466 870 Z"/>
|
|
439
|
+
<circle class="gs" cx="487" cy="849" r="6.5"/>
|
|
440
|
+
<circle class="gs" cx="474" cy="858" r="13"/>
|
|
441
|
+
<circle cx="469" cy="856" r="1.3" fill="#7d5f2a"/>
|
|
442
|
+
<path class="det" d="M486 902 C494 922 500 946 504 970" stroke-width="1.5"/>
|
|
443
|
+
<path class="det" d="M508 894 C516 916 520 942 522 966" stroke-width="1.5"/>
|
|
444
|
+
<path class="gs" d="M516 924 C524 924 530 930 530 938 C526 944 516 944 512 938 C512 930 512 926 516 924 Z"/>
|
|
445
|
+
<path class="det" d="M512 900 L520 924" stroke-width="1.5"/>
|
|
446
|
+
<rect class="hit" x="428" y="794" width="136" height="222"/>
|
|
447
|
+
</g>
|
|
448
|
+
|
|
449
|
+
<!-- the lantern at the quiet hours -->
|
|
450
|
+
<g id="lanternG" pointer-events="none">
|
|
451
|
+
<ellipse class="lg1" cx="428" cy="990" rx="27" ry="15"/>
|
|
452
|
+
<ellipse class="lg2" cx="428" cy="990" rx="14" ry="9"/>
|
|
453
|
+
<path class="lpost" d="M440 1006 C438 992 434 982 428 974"/>
|
|
454
|
+
<rect x="421" y="976" width="14" height="18" fill="#161009" stroke="#4a3d2a" stroke-width="2"/>
|
|
455
|
+
<path class="lflame" d="M428 982 L432 986 L428 990 L424 986 Z" fill="#e8b45c"/>
|
|
456
|
+
</g>
|
|
457
|
+
|
|
458
|
+
<!-- ======== THE MENDING + THE PULSE ======== -->
|
|
459
|
+
<g id="mendG" pointer-events="none">
|
|
460
|
+
<path class="seamBase" d="M410 900 L402 862 L410 824 L398 786 L406 748 L394 712 L402 676 L392 640 L400 604 L392 566"/>
|
|
461
|
+
<path class="seam" data-part="healer" d="M410 900 L402 862 L410 824 L398 786 L406 748 L394 712 L402 676 L392 640 L400 604 L392 566"/>
|
|
462
|
+
<path class="msp" data-part="healer" style="animation-delay:.2s" d="M405 794 L410 800 L405 806 L400 800 Z"/>
|
|
463
|
+
<path class="msp" data-part="healer" style="animation-delay:.9s" d="M399 694 L404 700 L399 706 L394 700 Z"/>
|
|
464
|
+
<path class="msp" data-part="healer" style="animation-delay:1.6s" d="M396 609 L401 615 L396 621 L391 615 Z"/>
|
|
465
|
+
<path class="vein" d="M366 792 C362 700 364 600 360 500 C358 440 362 380 374 336"/>
|
|
466
|
+
<path class="pdot" d="M366 792 C362 700 364 600 360 500 C358 440 362 380 374 336"/>
|
|
467
|
+
<path class="pdot p2" d="M366 792 C362 700 364 600 360 500 C358 440 362 380 374 336"/>
|
|
468
|
+
<path class="ptick" style="animation-delay:0s" d="M358 736 L363 729 L368 736 L363 743 Z"/>
|
|
469
|
+
<path class="ptick" style="animation-delay:-1.04s" d="M357 672 L362 665 L367 672 L362 679 Z"/>
|
|
470
|
+
<path class="ptick" style="animation-delay:-2.08s" d="M356 608 L361 601 L366 608 L361 615 Z"/>
|
|
471
|
+
<path class="ptick" style="animation-delay:-3.12s" d="M355 544 L360 537 L365 544 L360 551 Z"/>
|
|
472
|
+
<path class="ptick" style="animation-delay:-4.16s" d="M356 486 L361 479 L366 486 L361 493 Z"/>
|
|
473
|
+
</g>
|
|
474
|
+
|
|
475
|
+
<!-- new growth on the old wood (generated) -->
|
|
476
|
+
<g id="shootsG" pointer-events="none"></g>
|
|
477
|
+
|
|
478
|
+
<!-- connectors -->
|
|
479
|
+
<g id="links">
|
|
480
|
+
<path class="lnk" data-part="renewer" d="M196 745 C168 640 162 500 182 396"/>
|
|
481
|
+
<path class="lnk" data-part="renewer" d="M286 1002 C386 1016 486 1018 594 1002"/>
|
|
482
|
+
<path class="lnk" data-part="healer" d="M432 916 C424 910 416 906 410 902"/>
|
|
483
|
+
</g>
|
|
484
|
+
</svg>
|
|
485
|
+
</div>
|
|
486
|
+
</section>
|
|
487
|
+
|
|
488
|
+
<!-- ============ caption + plinth ============ -->
|
|
489
|
+
<section class="plate">
|
|
490
|
+
<p class="cap-hint"><b>◆</b> touch the renewer, the healer, or the road · the pulse on the trunk is the healing that never rests</p>
|
|
491
|
+
<p class="cap">hover or touch the carving —
|
|
492
|
+
<button data-p="renewer"><span class="rn">ᛒ</span>the renewer</button><i>·</i>
|
|
493
|
+
<button data-p="healer"><span class="rn">ᚹ</span>the healer</button><i>·</i>
|
|
494
|
+
<button data-p="road"><span class="rn">ᛚ</span>the road ahead</button>
|
|
495
|
+
</p>
|
|
496
|
+
|
|
497
|
+
<div class="plinth carved" id="plinth" aria-live="polite">
|
|
498
|
+
<div class="pl-head">
|
|
499
|
+
<span id="pRune">ᛒᚹ</span>
|
|
500
|
+
<div>
|
|
501
|
+
<p class="pl-k">the tending — touch a figure</p>
|
|
502
|
+
<p id="pName">Two Hands</p>
|
|
503
|
+
</div>
|
|
504
|
+
</div>
|
|
505
|
+
<div class="prow">
|
|
506
|
+
<span class="ptag">The myth</span>
|
|
507
|
+
<p class="pmyth" id="pMyth">One keeps the tree young; the other keeps it standing. Both are needed, and neither hurries.</p>
|
|
508
|
+
</div>
|
|
509
|
+
<div class="prow">
|
|
510
|
+
<span class="ptag">In Ymir</span>
|
|
511
|
+
<p class="pymir" id="pYmir">In Ymir: the renewer carries the tree forward; the healer makes whole what has cracked.</p>
|
|
512
|
+
</div>
|
|
513
|
+
</div>
|
|
514
|
+
|
|
515
|
+
<details class="unfold">
|
|
516
|
+
<summary><span class="rn">ᛒ</span>Unfold what is renewed and what is healed</summary>
|
|
517
|
+
<div class="tend-grid">
|
|
518
|
+
<div>
|
|
519
|
+
<p class="tg-k"><span class="rn">ᛒ</span>what is renewed</p>
|
|
520
|
+
<ul>
|
|
521
|
+
<li>the whole tree, carried to its newest shape — no branch broken</li>
|
|
522
|
+
<li>the old metal, coaxed back to life on the anvil</li>
|
|
523
|
+
<li>every hall's floor — versions and schemas kept whole as they move</li>
|
|
524
|
+
<li>the tools — sharpened by the update, never broken by it</li>
|
|
525
|
+
</ul>
|
|
526
|
+
</div>
|
|
527
|
+
<div>
|
|
528
|
+
<p class="tg-k"><span class="rn">ᚹ</span>what is healed</p>
|
|
529
|
+
<ul>
|
|
530
|
+
<li>what has cracked — found at the quiet hours, mended with gold</li>
|
|
531
|
+
<li>the stuck worker — recovered or replaced, never left in silence</li>
|
|
532
|
+
<li>the failing run — retraced, mended, watched again</li>
|
|
533
|
+
<li>the halls — walked nightly, kept standing, asking nothing</li>
|
|
534
|
+
</ul>
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
<p class="tg-road"><span class="rn">ᛚ</span>and the road ahead is mended while the smiths sleep — past the last marker, the Rut-steel reforging waits.</p>
|
|
538
|
+
</details>
|
|
539
|
+
|
|
540
|
+
<blockquote class="pull">One keeps the tree young; the other keeps it standing.
|
|
541
|
+
<small>the lore · §XII</small></blockquote>
|
|
542
|
+
|
|
543
|
+
<div class="pl-actions">
|
|
544
|
+
<button class="btn-carv" id="tourBtn"><span class="rn">ᚠ</span><span id="tourLabel">tend the tree</span></button>
|
|
545
|
+
</div>
|
|
546
|
+
</section>
|
|
547
|
+
</main>
|
|
548
|
+
|
|
549
|
+
<footer>
|
|
550
|
+
<div class="frule"><span>ᚠ ᚢ ᚦ ᚨ ᚱ ᚲ ᚷ ᚹ ᚺ ᚾ ᛁ ᛇ ᛈ ᛉ ᛊ ᛏ ᛒ ᛖ ᛗ ᛚ ᛜ ᛞ ᛟ</span></div>
|
|
551
|
+
<p class="f-big">The work is long — the tending is quiet.</p>
|
|
552
|
+
<p class="f-mono">renew · heal · walk on</p>
|
|
553
|
+
<p class="f-repo">zerwiz/ymir · docs/design.md · the lore · §XII</p>
|
|
554
|
+
</footer>
|
|
555
|
+
|
|
556
|
+
<script>
|
|
557
|
+
(function(){
|
|
558
|
+
'use strict';
|
|
559
|
+
const $ = s => document.querySelector(s);
|
|
560
|
+
const $$ = s => Array.from(document.querySelectorAll(s));
|
|
561
|
+
const NS = 'http://www.w3.org/2000/svg';
|
|
562
|
+
const RM = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
563
|
+
|
|
564
|
+
/* ---------- generated texture: stars, crown dust, ground hatch, new growth ---------- */
|
|
565
|
+
const STARS = [[66,110],[108,196],[84,286],[300,48],[500,44],[560,84],[712,236],[738,190],[700,420]];
|
|
566
|
+
STARS.forEach(([x,y],i)=>{
|
|
567
|
+
const s = 4.5 + (i % 3);
|
|
568
|
+
const p = document.createElementNS(NS,'path');
|
|
569
|
+
p.setAttribute('d', `M${x} ${y-s} L${x+s*.33} ${y-s*.33} L${x+s} ${y} L${x+s*.33} ${y+s*.33}
|
|
570
|
+
L${x} ${y+s} L${x-s*.33} ${y+s*.33} L${x-s} ${y} L${x-s*.33} ${y-s*.33} Z`);
|
|
571
|
+
p.setAttribute('class','star');
|
|
572
|
+
p.style.animationDelay = (-(i*0.85)) + 's';
|
|
573
|
+
p.style.animationDuration = (3.4 + (i%4)*.9) + 's';
|
|
574
|
+
$('#skyStars').appendChild(p);
|
|
575
|
+
});
|
|
576
|
+
(function(){
|
|
577
|
+
let dd = '', db = '';
|
|
578
|
+
for(let i = 0; i < 24; i++){
|
|
579
|
+
const x = (180 + Math.random()*400).toFixed(1), y = (130 + Math.random()*190).toFixed(1);
|
|
580
|
+
const s = (1.6 + Math.random()*2.6).toFixed(1);
|
|
581
|
+
const m = `M${x} ${y}l${s} -${s}l${s} ${s}l-${s} ${s}z`;
|
|
582
|
+
if(i % 3 === 0) db += m; else dd += m;
|
|
583
|
+
}
|
|
584
|
+
[['#2b2214', dd], ['#3f3219', db]].forEach(([f, d]) => {
|
|
585
|
+
const p = document.createElementNS(NS,'path');
|
|
586
|
+
p.setAttribute('d', d); p.setAttribute('fill', f);
|
|
587
|
+
$('#leafDust').appendChild(p);
|
|
588
|
+
});
|
|
589
|
+
let rh = '';
|
|
590
|
+
for(let x = 72; x <= 736; x += 24) rh += `M${x} 1009 l-8 9 `;
|
|
591
|
+
$('#ridgeHatch').setAttribute('d', rh);
|
|
592
|
+
})();
|
|
593
|
+
const LEAVES = [[168,326,-25],[184,340,-10],[200,358,-35],[216,384,15],[228,372,30],[240,356,50]];
|
|
594
|
+
LEAVES.forEach(([x,y,r],i)=>{
|
|
595
|
+
const g = document.createElementNS(NS,'g');
|
|
596
|
+
g.setAttribute('transform', `translate(${x} ${y}) rotate(${r})`);
|
|
597
|
+
const p = document.createElementNS(NS,'path');
|
|
598
|
+
p.setAttribute('class','shoot');
|
|
599
|
+
p.setAttribute('data-part','renewer');
|
|
600
|
+
p.setAttribute('d','M0 0 C-5 -7 1 -14 8 -11 C10 -4 4 2 0 0 Z');
|
|
601
|
+
p.style.animationDelay = (i*95) + 'ms';
|
|
602
|
+
g.appendChild(p);
|
|
603
|
+
$('#shootsG').appendChild(g);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
/* ---------- the carving speaks ---------- */
|
|
607
|
+
const PARTS = {
|
|
608
|
+
renewer:{ rune:'ᛒ', name:'the renewer',
|
|
609
|
+
myth:'A wise-woman whose hands coax the old metal back to life — she carries the whole tree forward to its newest shape without breaking a single branch, and mends the road ahead while the smiths sleep.',
|
|
610
|
+
ymir:'The carrying hand — versions carried forward, migrations that keep every hall whole; the self-update that only sharpens the tools, never breaks the forge.'},
|
|
611
|
+
healer:{ rune:'ᚹ', name:'the healer',
|
|
612
|
+
myth:'A gentle one who walks the halls at quiet hours, finds what has cracked, and makes it whole again — asking nothing in return.',
|
|
613
|
+
ymir:'The mending hand — the stuck worker recovered, the failing run retraced, every soul kept alive and watched; a run that is not watched cannot be trusted.'},
|
|
614
|
+
road:{ rune:'ᛚ', name:'the road ahead',
|
|
615
|
+
myth:'The road runs on from the tree — mended by the renewer while the smiths sleep, walked by the fleet when the day returns.',
|
|
616
|
+
ymir:'The way on — past the last marker waits the Rut-steel reforging: every gate re-floored one-for-one; the contract stays the same, only the metal changes.'}
|
|
617
|
+
};
|
|
618
|
+
const plinth = $('#plinth');
|
|
619
|
+
let swapT = null, pinned = null, touring = false;
|
|
620
|
+
|
|
621
|
+
function light(p){
|
|
622
|
+
$$('[data-part]').forEach(el =>
|
|
623
|
+
el.classList.toggle('lit', !!p && el.dataset.part === p));
|
|
624
|
+
const sc = $('#scene');
|
|
625
|
+
sc.classList.toggle('focus', !!p);
|
|
626
|
+
sc.classList.toggle('healing', p === 'healer');
|
|
627
|
+
$$('.cap button').forEach(b => b.classList.toggle('on', !!p && b.dataset.p === p));
|
|
628
|
+
plinth.classList.add('swap');
|
|
629
|
+
clearTimeout(swapT);
|
|
630
|
+
swapT = setTimeout(() => {
|
|
631
|
+
$('#pRune').textContent = p ? PARTS[p].rune : 'ᛒᚹ';
|
|
632
|
+
$('#pName').textContent = p ? PARTS[p].name : 'Two Hands';
|
|
633
|
+
$('#pMyth').textContent = p ? PARTS[p].myth :
|
|
634
|
+
'One keeps the tree young; the other keeps it standing. Both are needed, and neither hurries.';
|
|
635
|
+
$('#pYmir').textContent = p ? PARTS[p].ymir :
|
|
636
|
+
'In Ymir: the renewer carries the tree forward; the healer makes whole what has cracked.';
|
|
637
|
+
plinth.classList.remove('swap');
|
|
638
|
+
}, 170);
|
|
639
|
+
}
|
|
640
|
+
function hook(el, p){
|
|
641
|
+
el.addEventListener('mouseenter', () => { if(!touring) light(p); });
|
|
642
|
+
el.addEventListener('mouseleave', () => { if(!touring) light(pinned); });
|
|
643
|
+
const act = () => { pinned = (pinned === p) ? null : p; light(pinned); };
|
|
644
|
+
el.addEventListener('click', act);
|
|
645
|
+
el.addEventListener('keydown', e => {
|
|
646
|
+
if(e.key === 'Enter' || e.key === ' '){ e.preventDefault(); act(); }
|
|
647
|
+
});
|
|
648
|
+
el.addEventListener('focus', () => { if(!touring) light(p); });
|
|
649
|
+
el.addEventListener('blur', () => { if(!touring) light(pinned); });
|
|
650
|
+
}
|
|
651
|
+
$$('#scene g[data-part]').forEach(g => hook(g, g.dataset.part));
|
|
652
|
+
$$('.cap button').forEach(b => hook(b, b.dataset.p));
|
|
653
|
+
|
|
654
|
+
/* ---------- the tending: renewer → healer → road ---------- */
|
|
655
|
+
$('#tourBtn').addEventListener('click', () => {
|
|
656
|
+
if(touring) return;
|
|
657
|
+
touring = true; pinned = null;
|
|
658
|
+
const btn = $('#tourBtn');
|
|
659
|
+
btn.classList.add('busy');
|
|
660
|
+
$('#tourLabel').textContent = 'neither hurries';
|
|
661
|
+
const order = ['renewer','healer','road'];
|
|
662
|
+
let i = 0;
|
|
663
|
+
(function step(){
|
|
664
|
+
if(i < order.length){ light(order[i++]); setTimeout(step, 2600); }
|
|
665
|
+
else{
|
|
666
|
+
light(null); touring = false;
|
|
667
|
+
btn.classList.remove('busy');
|
|
668
|
+
$('#tourLabel').textContent = 'tend the tree';
|
|
669
|
+
}
|
|
670
|
+
})();
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
/* ---------- ambience: cold night, fireflies, sleeping forge ---------- */
|
|
674
|
+
(function(){
|
|
675
|
+
const cv = $('#gap'), ctx = cv.getContext('2d');
|
|
676
|
+
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
677
|
+
let W = 0, H = 0, mist = [], flies = [], t = 0;
|
|
678
|
+
function size(){
|
|
679
|
+
W = innerWidth; H = innerHeight;
|
|
680
|
+
cv.width = W*dpr; cv.height = H*dpr;
|
|
681
|
+
ctx.setTransform(dpr,0,0,dpr,0,0);
|
|
682
|
+
}
|
|
683
|
+
function init(){
|
|
684
|
+
mist = []; flies = [];
|
|
685
|
+
for(let i=0;i<6;i++) mist.push({ x:Math.random()*W, y:H*.2+Math.random()*H*.7,
|
|
686
|
+
r:170+Math.random()*230, v:(Math.random()-.5)*.13 });
|
|
687
|
+
for(let i=0;i<7;i++) flies.push({ x:Math.random()*W, y:H*.55+Math.random()*H*.4,
|
|
688
|
+
r:1+Math.random()*.8, ph:Math.random()*6.28, sp:.18+Math.random()*.3 });
|
|
689
|
+
}
|
|
690
|
+
function frame(){
|
|
691
|
+
t += .016; ctx.clearRect(0,0,W,H);
|
|
692
|
+
for(const m of mist){
|
|
693
|
+
m.x += m.v;
|
|
694
|
+
if(m.x < -m.r) m.x = W+m.r;
|
|
695
|
+
if(m.x > W+m.r) m.x = -m.r;
|
|
696
|
+
const g = ctx.createRadialGradient(m.x,m.y,0,m.x,m.y,m.r);
|
|
697
|
+
g.addColorStop(0,'rgba(96,110,128,.05)');
|
|
698
|
+
g.addColorStop(1,'rgba(0,0,0,0)');
|
|
699
|
+
ctx.fillStyle = g;
|
|
700
|
+
ctx.beginPath(); ctx.arc(m.x,m.y,m.r,0,6.283); ctx.fill();
|
|
701
|
+
}
|
|
702
|
+
for(const f of flies){
|
|
703
|
+
f.x += Math.sin(t*f.sp*3 + f.ph)*.28;
|
|
704
|
+
f.y += Math.cos(t*f.sp*2.4 + f.ph)*.2;
|
|
705
|
+
const a = .06 + .3*(.5 + .5*Math.sin(t*1.4 + f.ph*2));
|
|
706
|
+
ctx.fillStyle = `rgba(224,190,120,${a.toFixed(3)})`;
|
|
707
|
+
ctx.beginPath(); ctx.arc(f.x,f.y,f.r,0,6.283); ctx.fill();
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
addEventListener('resize', () => { size(); init(); if(RM) frame(); });
|
|
711
|
+
size(); init();
|
|
712
|
+
if(RM) frame(); else (function loop(){ frame(); requestAnimationFrame(loop); })();
|
|
713
|
+
})();
|
|
714
|
+
})();
|
|
715
|
+
</script>
|
|
716
|
+
</body>
|
|
717
|
+
</html>
|