sumulige-claude 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/.claude/hooks/hook-registry.json +0 -15
  2. package/.claude/rules/coding-style.md +18 -7
  3. package/.claude/rules/hooks.md +15 -4
  4. package/.claude/rules/performance.md +15 -5
  5. package/.claude/rules/security.md +140 -4
  6. package/.claude/rules/testing.md +138 -9
  7. package/.claude/rules/web-design-standard.md +16 -5
  8. package/.claude/skills/algorithmic-art/metadata.yaml +28 -0
  9. package/.claude/skills/api-tester/SKILL.md +61 -0
  10. package/.claude/skills/api-tester/examples/basic.md +3 -0
  11. package/.claude/skills/api-tester/metadata.yaml +30 -0
  12. package/.claude/skills/api-tester/templates/default.md +3 -0
  13. package/.claude/skills/brand-guidelines/metadata.yaml +26 -0
  14. package/.claude/skills/canvas-design/metadata.yaml +27 -0
  15. package/.claude/skills/code-reviewer-123/SKILL.md +61 -0
  16. package/.claude/skills/code-reviewer-123/examples/basic.md +3 -0
  17. package/.claude/skills/code-reviewer-123/metadata.yaml +30 -0
  18. package/.claude/skills/code-reviewer-123/templates/default.md +3 -0
  19. package/.claude/skills/doc-coauthoring/metadata.yaml +27 -0
  20. package/.claude/skills/docx/metadata.yaml +30 -0
  21. package/.claude/skills/frontend-design/metadata.yaml +28 -0
  22. package/.claude/skills/internal-comms/metadata.yaml +28 -0
  23. package/.claude/skills/mcp-builder/metadata.yaml +26 -0
  24. package/.claude/skills/my-skill/SKILL.md +61 -0
  25. package/.claude/skills/my-skill/examples/basic.md +3 -0
  26. package/.claude/skills/my-skill/metadata.yaml +30 -0
  27. package/.claude/skills/my-skill/templates/default.md +3 -0
  28. package/.claude/skills/pdf/metadata.yaml +29 -0
  29. package/.claude/skills/pptx/metadata.yaml +29 -0
  30. package/.claude/skills/react-best-practices/metadata.yaml +26 -0
  31. package/.claude/skills/react-node-practices/SKILL.md +409 -0
  32. package/.claude/skills/react-node-practices/metadata.yaml +56 -0
  33. package/.claude/skills/skill-creator/metadata.yaml +25 -0
  34. package/.claude/skills/slack-gif-creator/metadata.yaml +28 -0
  35. package/.claude/skills/test-skill-name/SKILL.md +61 -0
  36. package/.claude/skills/test-skill-name/examples/basic.md +3 -0
  37. package/.claude/skills/test-skill-name/metadata.yaml +30 -0
  38. package/.claude/skills/test-skill-name/templates/default.md +3 -0
  39. package/.claude/skills/test-workflow/metadata.yaml +32 -0
  40. package/.claude/skills/theme-factory/metadata.yaml +26 -0
  41. package/.claude/skills/threejs-fundamentals/metadata.yaml +27 -0
  42. package/.claude/skills/web-artifacts-builder/metadata.yaml +30 -0
  43. package/.claude/skills/web-design-guidelines/metadata.yaml +26 -0
  44. package/.claude/skills/webapp-testing/metadata.yaml +26 -0
  45. package/.claude/skills/xlsx/metadata.yaml +29 -0
  46. package/LICENSE +21 -0
  47. package/README.md +280 -529
  48. package/cli.js +19 -3
  49. package/package.json +29 -3
  50. package/template/.codex/README.md +69 -0
  51. package/template/.codex/config.toml +56 -0
  52. package/template/AGENTS.md +94 -0
  53. package/.claude/.kickoff-hint.txt +0 -52
  54. package/.claude/.sumulige-claude-version +0 -1
  55. package/.claude/.version +0 -1
  56. package/.claude/AGENTS.md +0 -42
  57. package/.claude/ANCHORS.md +0 -40
  58. package/.claude/CLAUDE.md +0 -138
  59. package/.claude/MEMORY.md +0 -69
  60. package/.claude/PROJECT_LOG.md +0 -101
  61. package/.claude/THINKING_CHAIN_GUIDE.md +0 -287
  62. package/.claude/USAGE.md +0 -175
  63. package/.claude/boris-optimizations.md +0 -167
  64. package/.claude/handoffs/INDEX.md +0 -21
  65. package/.claude/handoffs/LATEST.md +0 -76
  66. package/.claude/handoffs/handoff_2026-01-22T13-07-04-757Z.md +0 -76
  67. package/.claude/quality-gate.json +0 -82
  68. package/.claude/rag/skill-index.json +0 -135
  69. package/.claude/settings.json +0 -99
  70. package/.claude/settings.local.json +0 -175
  71. package/.claude/templates/PROJECT_KICKOFF.md +0 -89
  72. package/.claude/templates/PROJECT_PROPOSAL.md +0 -227
  73. package/.claude/templates/TASK_PLAN.md +0 -121
  74. package/.claude/templates/hooks/README.md +0 -302
  75. package/.claude/templates/hooks/hook.sh.template +0 -94
  76. package/.claude/templates/hooks/user-prompt-submit.cjs.template +0 -116
  77. package/.claude/templates/hooks/user-response-submit.cjs.template +0 -94
  78. package/.claude/templates/hooks/validate.js +0 -173
  79. package/.claude/templates/tasks/develop.md +0 -69
  80. package/.claude/templates/tasks/research.md +0 -64
  81. package/.claude/templates/tasks/test.md +0 -96
  82. package/.claude/thinking-routes/.last-sync +0 -1
  83. package/.claude/thinking-routes/QUICKREF.md +0 -98
  84. package/.claude/workflow/document-scanner.js +0 -426
  85. package/.claude/workflow/knowledge-engine.js +0 -941
  86. package/.claude/workflow/notebooklm/browser.js +0 -1028
  87. package/.claude/workflow/phases/phase1-research.js +0 -578
  88. package/.claude/workflow/phases/phase1-research.ts +0 -465
  89. package/.claude/workflow/phases/phase2-approve.js +0 -722
  90. package/.claude/workflow/phases/phase3-plan.js +0 -1200
  91. package/.claude/workflow/phases/phase4-develop.js +0 -894
  92. package/.claude/workflow/search-cache.js +0 -230
  93. package/.claude/workflow/templates/approval.md +0 -315
  94. package/.claude/workflow/templates/development.md +0 -377
  95. package/.claude/workflow/templates/planning.md +0 -328
  96. package/.claude/workflow/templates/research.md +0 -250
  97. package/.claude/workflow/types.js +0 -37
  98. package/.claude/workflow/web-search.js +0 -278
  99. package/.claude-plugin/marketplace.json +0 -71
  100. package/.github/workflows/sync-skills.yml +0 -74
  101. package/.versionrc +0 -25
  102. package/AGENTS.md +0 -580
  103. package/CHANGELOG.md +0 -481
  104. package/CLAUDE-template.md +0 -114
  105. package/DEV_TOOLS_GUIDE.md +0 -190
  106. package/PROJECT_STRUCTURE.md +0 -266
  107. package/Q&A.md +0 -325
  108. package/config/defaults.json +0 -34
  109. package/config/official-skills.json +0 -183
  110. package/config/quality-gate.json +0 -67
  111. package/config/skill-categories.json +0 -40
  112. package/config/version-manifest.json +0 -85
  113. package/demos/power-3d-scatter.html +0 -683
  114. package/development/cache/web-search/search_1193d605f8eb364651fc2f2041b58a31.json +0 -36
  115. package/development/cache/web-search/search_3798bf06960edc125f744a1abb5b72c5.json +0 -36
  116. package/development/cache/web-search/search_37c7d4843a53f0d83f1122a6f908a2a3.json +0 -36
  117. package/development/cache/web-search/search_44166fa0153709ee168485a22aa0ab40.json +0 -36
  118. package/development/cache/web-search/search_4deaebb1f77e86a8ca066dc5a49c59fd.json +0 -36
  119. package/development/cache/web-search/search_94da91789466070a7f545612e73c7372.json +0 -36
  120. package/development/cache/web-search/search_dd5de8491b8b803a3cb01339cd210fb0.json +0 -36
  121. package/development/knowledge-base/.index.clean.json +0 -1
  122. package/development/knowledge-base/.index.json +0 -486
  123. package/development/knowledge-base/test-best-practices.md +0 -29
  124. package/development/projects/proj_mkh1pazz_ixmt1/phase1/feasibility-report.md +0 -160
  125. package/development/projects/proj_mkh4jvnb_z7rwf/phase1/feasibility-report.md +0 -160
  126. package/development/projects/proj_mkh4jxkd_ewz5a/phase1/feasibility-report.md +0 -160
  127. package/development/projects/proj_mkh4k84n_ni73k/phase1/feasibility-report.md +0 -160
  128. package/development/projects/proj_mkh4wfyd_u9w88/phase1/feasibility-report.md +0 -160
  129. package/development/projects/proj_mkh4wsbo_iahvf/development/projects/proj_mkh4xbpg_4na5w/phase1/feasibility-report.md +0 -160
  130. package/development/projects/proj_mkh4wsbo_iahvf/phase1/feasibility-report.md +0 -160
  131. package/development/projects/proj_mkh4xulg_1ka8x/phase1/feasibility-report.md +0 -160
  132. package/development/projects/proj_mkh4xwhj_gch8j/phase1/feasibility-report.md +0 -160
  133. package/development/projects/proj_mkh4y2qk_9lm8z/phase1/feasibility-report.md +0 -160
  134. package/development/projects/proj_mkh4y2qk_9lm8z/phase2/requirements.md +0 -226
  135. package/development/projects/proj_mkh4y2qk_9lm8z/phase3/PRD.md +0 -345
  136. package/development/projects/proj_mkh4y2qk_9lm8z/phase3/TASK_PLAN.md +0 -284
  137. package/development/projects/proj_mkh4y2qk_9lm8z/phase3/prototype/README.md +0 -14
  138. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/DEVELOPMENT_LOG.md +0 -35
  139. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/TASKS.md +0 -34
  140. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/.env.example +0 -5
  141. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/README.md +0 -60
  142. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/package.json +0 -25
  143. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/index.js +0 -70
  144. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/routes/index.js +0 -48
  145. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/health.test.js +0 -20
  146. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/jest.config.js +0 -21
  147. package/development/projects/proj_mkh7veqg_3lypc/phase1/feasibility-report.md +0 -160
  148. package/development/projects/proj_mkh7veqg_3lypc/phase2/requirements.md +0 -226
  149. package/development/projects/proj_mkh7veqg_3lypc/phase3/PRD.md +0 -345
  150. package/development/projects/proj_mkh7veqg_3lypc/phase3/TASK_PLAN.md +0 -284
  151. package/development/projects/proj_mkh7veqg_3lypc/phase3/prototype/README.md +0 -14
  152. package/development/projects/proj_mkh8k8fo_rmqn5/phase1/feasibility-report.md +0 -160
  153. package/development/projects/proj_mkh8xyhy_1vshq/phase1/feasibility-report.md +0 -178
  154. package/development/projects/proj_mkh8zddd_dhamf/phase1/feasibility-report.md +0 -377
  155. package/development/projects/proj_mkh8zddd_dhamf/phase2/requirements.md +0 -442
  156. package/development/projects/proj_mkh8zddd_dhamf/phase3/api-design.md +0 -800
  157. package/development/projects/proj_mkh8zddd_dhamf/phase3/architecture.md +0 -625
  158. package/development/projects/proj_mkh8zddd_dhamf/phase3/data-model.md +0 -830
  159. package/development/projects/proj_mkh8zddd_dhamf/phase3/risks.md +0 -957
  160. package/development/projects/proj_mkh8zddd_dhamf/phase3/wbs.md +0 -381
  161. package/development/todos/.state.json +0 -19
  162. package/development/todos/INDEX.md +0 -63
  163. package/development/todos/active/_README.md +0 -49
  164. package/development/todos/archived/_README.md +0 -11
  165. package/development/todos/backlog/_README.md +0 -11
  166. package/development/todos/backlog/mcp-integration.md +0 -35
  167. package/development/todos/completed/_README.md +0 -11
  168. package/development/todos/completed/boris-optimizations.md +0 -39
  169. package/development/todos/completed/develop/local-knowledge-index.md +0 -85
  170. package/development/todos/completed/develop/todo-system.md +0 -47
  171. package/development/todos/completed/develop/web-search-integration.md +0 -83
  172. package/development/todos/completed/test/phase1-e2e-test.md +0 -103
  173. package/docs/DEVELOPMENT.md +0 -461
  174. package/docs/MARKETPLACE.md +0 -352
  175. package/docs/RELEASE.md +0 -93
  176. package/jest.config.js +0 -63
  177. package/lib/commands.js +0 -3588
  178. package/lib/config-manager.js +0 -441
  179. package/lib/config-schema.js +0 -408
  180. package/lib/config-validator.js +0 -330
  181. package/lib/config.js +0 -122
  182. package/lib/errors.js +0 -305
  183. package/lib/incremental-sync.js +0 -274
  184. package/lib/marketplace.js +0 -487
  185. package/lib/migrations.js +0 -154
  186. package/lib/permission-audit.js +0 -255
  187. package/lib/quality-gate.js +0 -431
  188. package/lib/quality-rules.js +0 -373
  189. package/lib/utils.js +0 -150
  190. package/lib/version-check.js +0 -169
  191. package/lib/version-manifest.js +0 -171
  192. package/project-paradigm.md +0 -313
  193. package/prompts/how-to-find.md +0 -163
  194. package/prompts/linus-architect.md +0 -71
  195. package/prompts/software-architect.md +0 -173
  196. package/prompts/web-designer.md +0 -249
  197. package/scripts/fix-hooks.mjs +0 -97
  198. package/scripts/sync-external.mjs +0 -298
  199. package/scripts/sync-to-home.sh +0 -108
  200. package/scripts/update-registry.mjs +0 -325
  201. package/sources.yaml +0 -83
  202. package/tests/README.md +0 -263
  203. package/tests/commands.test.js +0 -1086
  204. package/tests/config-manager.test.js +0 -677
  205. package/tests/config-schema.test.js +0 -425
  206. package/tests/config-validator.test.js +0 -436
  207. package/tests/config.test.js +0 -100
  208. package/tests/errors.test.js +0 -477
  209. package/tests/manual/phase1-e2e.sh +0 -389
  210. package/tests/manual/phase2-test-cases.md +0 -311
  211. package/tests/manual/phase3-test-cases.md +0 -309
  212. package/tests/manual/phase4-test-cases.md +0 -414
  213. package/tests/manual/test-cases.md +0 -417
  214. package/tests/marketplace.test.js +0 -420
  215. package/tests/migrations.test.js +0 -187
  216. package/tests/quality-gate.test.js +0 -679
  217. package/tests/quality-rules.test.js +0 -619
  218. package/tests/sync-external.test.js +0 -214
  219. package/tests/update-registry.test.js +0 -251
  220. package/tests/utils.test.js +0 -171
  221. package/tests/version-check.test.js +0 -75
  222. package/tests/web-search.test.js +0 -392
  223. package/thinkinglens-silent.md +0 -138
@@ -1,683 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="zh">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>ApexOS - 3D Power Analysis</title>
7
- <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
12
- }
13
-
14
- body {
15
- font-family: 'JetBrains Mono', 'SF Mono', monospace;
16
- background: #0a0a0a;
17
- color: #fff;
18
- overflow: hidden;
19
- }
20
-
21
- #container {
22
- width: 100vw;
23
- height: 100vh;
24
- position: relative;
25
- }
26
-
27
- #info {
28
- position: absolute;
29
- top: 20px;
30
- left: 20px;
31
- z-index: 100;
32
- background: rgba(0, 0, 0, 0.8);
33
- padding: 20px;
34
- border-radius: 12px;
35
- border: 1px solid rgba(255, 255, 255, 0.1);
36
- backdrop-filter: blur(10px);
37
- max-width: 320px;
38
- }
39
-
40
- #info h1 {
41
- font-size: 18px;
42
- font-weight: 600;
43
- margin-bottom: 8px;
44
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
45
- -webkit-background-clip: text;
46
- -webkit-text-fill-color: transparent;
47
- background-clip: text;
48
- }
49
-
50
- #info p {
51
- font-size: 12px;
52
- color: #888;
53
- line-height: 1.6;
54
- margin-bottom: 16px;
55
- }
56
-
57
- .legend {
58
- display: flex;
59
- flex-direction: column;
60
- gap: 8px;
61
- }
62
-
63
- .legend-item {
64
- display: flex;
65
- align-items: center;
66
- gap: 10px;
67
- font-size: 12px;
68
- }
69
-
70
- .legend-color {
71
- width: 12px;
72
- height: 12px;
73
- border-radius: 50%;
74
- }
75
-
76
- .legend-label {
77
- color: #aaa;
78
- }
79
-
80
- .legend-value {
81
- margin-left: auto;
82
- font-variant-numeric: tabular-nums;
83
- color: #fff;
84
- }
85
-
86
- #stats {
87
- position: absolute;
88
- top: 20px;
89
- right: 20px;
90
- z-index: 100;
91
- background: rgba(0, 0, 0, 0.8);
92
- padding: 16px 20px;
93
- border-radius: 12px;
94
- border: 1px solid rgba(255, 255, 255, 0.1);
95
- backdrop-filter: blur(10px);
96
- }
97
-
98
- .stat-row {
99
- display: flex;
100
- justify-content: space-between;
101
- gap: 40px;
102
- margin-bottom: 8px;
103
- }
104
-
105
- .stat-row:last-child {
106
- margin-bottom: 0;
107
- }
108
-
109
- .stat-label {
110
- font-size: 11px;
111
- color: #666;
112
- text-transform: uppercase;
113
- letter-spacing: 0.5px;
114
- }
115
-
116
- .stat-value {
117
- font-size: 14px;
118
- font-weight: 600;
119
- font-variant-numeric: tabular-nums;
120
- }
121
-
122
- .stat-value.power { color: #667eea; }
123
- .stat-value.hr { color: #f56565; }
124
- .stat-value.time { color: #48bb78; }
125
-
126
- #tooltip {
127
- position: absolute;
128
- background: rgba(0, 0, 0, 0.9);
129
- padding: 12px 16px;
130
- border-radius: 8px;
131
- border: 1px solid rgba(255, 255, 255, 0.2);
132
- font-size: 12px;
133
- pointer-events: none;
134
- opacity: 0;
135
- transition: opacity 0.2s;
136
- z-index: 200;
137
- }
138
-
139
- #tooltip.visible {
140
- opacity: 1;
141
- }
142
-
143
- #controls {
144
- position: absolute;
145
- bottom: 20px;
146
- left: 50%;
147
- transform: translateX(-50%);
148
- z-index: 100;
149
- display: flex;
150
- gap: 12px;
151
- }
152
-
153
- .control-btn {
154
- background: rgba(255, 255, 255, 0.1);
155
- border: 1px solid rgba(255, 255, 255, 0.2);
156
- color: #fff;
157
- padding: 10px 20px;
158
- border-radius: 8px;
159
- cursor: pointer;
160
- font-size: 12px;
161
- font-family: inherit;
162
- transition: all 0.2s;
163
- }
164
-
165
- .control-btn:hover {
166
- background: rgba(255, 255, 255, 0.2);
167
- border-color: rgba(255, 255, 255, 0.3);
168
- }
169
-
170
- .control-btn.active {
171
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
172
- border-color: transparent;
173
- }
174
-
175
- /* Axis labels */
176
- .axis-label {
177
- position: absolute;
178
- font-size: 11px;
179
- color: #666;
180
- text-transform: uppercase;
181
- letter-spacing: 1px;
182
- }
183
-
184
- #x-label { bottom: 60px; left: 50%; transform: translateX(-50%); }
185
- #y-label { left: 20px; top: 50%; transform: rotate(-90deg) translateX(-50%); transform-origin: left center; }
186
- #z-label { right: 60px; bottom: 50%; }
187
- </style>
188
- </head>
189
- <body>
190
- <div id="container"></div>
191
-
192
- <div id="info">
193
- <h1>3D Power Analysis</h1>
194
- <p>Visualizing the relationship between Power, Time, and Heart Rate during your ride.</p>
195
- <div class="legend">
196
- <div class="legend-item">
197
- <div class="legend-color" style="background: #667eea;"></div>
198
- <span class="legend-label">X-Axis: Time</span>
199
- <span class="legend-value">0-60 min</span>
200
- </div>
201
- <div class="legend-item">
202
- <div class="legend-color" style="background: #48bb78;"></div>
203
- <span class="legend-label">Y-Axis: Power</span>
204
- <span class="legend-value">0-400 W</span>
205
- </div>
206
- <div class="legend-item">
207
- <div class="legend-color" style="background: #f56565;"></div>
208
- <span class="legend-label">Z-Axis: Heart Rate</span>
209
- <span class="legend-value">100-180 bpm</span>
210
- </div>
211
- </div>
212
- </div>
213
-
214
- <div id="stats">
215
- <div class="stat-row">
216
- <span class="stat-label">Avg Power</span>
217
- <span class="stat-value power" id="avg-power">--</span>
218
- </div>
219
- <div class="stat-row">
220
- <span class="stat-label">Avg HR</span>
221
- <span class="stat-value hr" id="avg-hr">--</span>
222
- </div>
223
- <div class="stat-row">
224
- <span class="stat-label">Duration</span>
225
- <span class="stat-value time" id="duration">--</span>
226
- </div>
227
- <div class="stat-row">
228
- <span class="stat-label">Data Points</span>
229
- <span class="stat-value" id="points">--</span>
230
- </div>
231
- </div>
232
-
233
- <div id="tooltip"></div>
234
-
235
- <div id="controls">
236
- <button class="control-btn active" data-view="perspective">Perspective</button>
237
- <button class="control-btn" data-view="top">Top (Time-Power)</button>
238
- <button class="control-btn" data-view="front">Front (Power-HR)</button>
239
- <button class="control-btn" data-view="side">Side (Time-HR)</button>
240
- <button class="control-btn" data-action="animate">Auto Rotate</button>
241
- </div>
242
-
243
- <script type="importmap">
244
- {
245
- "imports": {
246
- "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
247
- "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
248
- }
249
- }
250
- </script>
251
-
252
- <script type="module">
253
- import * as THREE from 'three';
254
- import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
255
-
256
- // ============ Configuration ============
257
- const CONFIG = {
258
- pointCount: 600, // 10 points per minute for 60 min
259
- pointSize: 0.08,
260
- axisSize: 8,
261
- gridDivisions: 10,
262
- colors: {
263
- power: 0x667eea, // Purple-blue
264
- hr: 0xf56565, // Red
265
- time: 0x48bb78, // Green
266
- grid: 0x333333,
267
- background: 0x0a0a0a
268
- }
269
- };
270
-
271
- // ============ Generate Cycling Data ============
272
- function generateCyclingData(pointCount) {
273
- const data = [];
274
- const duration = 60; // 60 minutes
275
-
276
- // Simulate a structured workout:
277
- // 0-10 min: Warmup
278
- // 10-20 min: Intervals (high power)
279
- // 20-35 min: Steady state
280
- // 35-50 min: More intervals
281
- // 50-60 min: Cooldown
282
-
283
- for (let i = 0; i < pointCount; i++) {
284
- const t = (i / pointCount) * duration;
285
-
286
- let basePower, baseHR;
287
-
288
- if (t < 10) {
289
- // Warmup: gradually increasing
290
- basePower = 150 + (t / 10) * 50;
291
- baseHR = 110 + (t / 10) * 20;
292
- } else if (t < 20) {
293
- // Intervals: high power spikes
294
- const intervalPhase = ((t - 10) % 2) / 2;
295
- basePower = intervalPhase < 0.5 ? 320 : 180;
296
- baseHR = intervalPhase < 0.5 ? 165 : 140;
297
- } else if (t < 35) {
298
- // Steady state
299
- basePower = 240;
300
- baseHR = 150;
301
- } else if (t < 50) {
302
- // More intense intervals
303
- const intervalPhase = ((t - 35) % 1.5) / 1.5;
304
- basePower = intervalPhase < 0.6 ? 350 : 200;
305
- baseHR = intervalPhase < 0.6 ? 175 : 145;
306
- } else {
307
- // Cooldown
308
- const cooldownProgress = (t - 50) / 10;
309
- basePower = 200 - cooldownProgress * 80;
310
- baseHR = 145 - cooldownProgress * 30;
311
- }
312
-
313
- // Add realistic noise
314
- const noise = () => (Math.random() - 0.5) * 2;
315
- const power = Math.max(50, basePower + noise() * 30);
316
- const hr = Math.max(90, Math.min(190, baseHR + noise() * 8));
317
-
318
- data.push({
319
- time: t,
320
- power: power,
321
- hr: hr,
322
- // Calculate intensity zone for coloring
323
- intensity: power > 300 ? 'high' : power > 220 ? 'medium' : 'low'
324
- });
325
- }
326
-
327
- return data;
328
- }
329
-
330
- // ============ Scene Setup ============
331
- const container = document.getElementById('container');
332
- const scene = new THREE.Scene();
333
- scene.background = new THREE.Color(CONFIG.colors.background);
334
-
335
- const camera = new THREE.PerspectiveCamera(
336
- 60,
337
- window.innerWidth / window.innerHeight,
338
- 0.1,
339
- 1000
340
- );
341
- camera.position.set(12, 10, 12);
342
-
343
- const renderer = new THREE.WebGLRenderer({
344
- antialias: true,
345
- alpha: true
346
- });
347
- renderer.setSize(window.innerWidth, window.innerHeight);
348
- renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
349
- container.appendChild(renderer.domElement);
350
-
351
- // Controls
352
- const controls = new OrbitControls(camera, renderer.domElement);
353
- controls.enableDamping = true;
354
- controls.dampingFactor = 0.05;
355
- controls.minDistance = 5;
356
- controls.maxDistance = 30;
357
-
358
- // ============ Create Axes ============
359
- function createAxes() {
360
- const axisGroup = new THREE.Group();
361
- const size = CONFIG.axisSize;
362
-
363
- // Axis lines with glow effect
364
- const axisMaterial = (color) => new THREE.LineBasicMaterial({
365
- color,
366
- linewidth: 2,
367
- transparent: true,
368
- opacity: 0.8
369
- });
370
-
371
- // X-axis (Time) - Blue-purple
372
- const xGeom = new THREE.BufferGeometry().setFromPoints([
373
- new THREE.Vector3(0, 0, 0),
374
- new THREE.Vector3(size, 0, 0)
375
- ]);
376
- axisGroup.add(new THREE.Line(xGeom, axisMaterial(CONFIG.colors.power)));
377
-
378
- // Y-axis (Power) - Green
379
- const yGeom = new THREE.BufferGeometry().setFromPoints([
380
- new THREE.Vector3(0, 0, 0),
381
- new THREE.Vector3(0, size, 0)
382
- ]);
383
- axisGroup.add(new THREE.Line(yGeom, axisMaterial(CONFIG.colors.time)));
384
-
385
- // Z-axis (HR) - Red
386
- const zGeom = new THREE.BufferGeometry().setFromPoints([
387
- new THREE.Vector3(0, 0, 0),
388
- new THREE.Vector3(0, 0, size)
389
- ]);
390
- axisGroup.add(new THREE.Line(zGeom, axisMaterial(CONFIG.colors.hr)));
391
-
392
- // Grid on XZ plane (bottom)
393
- const gridXZ = new THREE.GridHelper(size, CONFIG.gridDivisions, CONFIG.colors.grid, CONFIG.colors.grid);
394
- gridXZ.position.set(size/2, 0, size/2);
395
- gridXZ.material.transparent = true;
396
- gridXZ.material.opacity = 0.3;
397
- axisGroup.add(gridXZ);
398
-
399
- // Grid on XY plane (back)
400
- const gridXY = new THREE.GridHelper(size, CONFIG.gridDivisions, CONFIG.colors.grid, CONFIG.colors.grid);
401
- gridXY.rotation.x = Math.PI / 2;
402
- gridXY.position.set(size/2, size/2, 0);
403
- gridXY.material.transparent = true;
404
- gridXY.material.opacity = 0.2;
405
- axisGroup.add(gridXY);
406
-
407
- // Grid on YZ plane (left)
408
- const gridYZ = new THREE.GridHelper(size, CONFIG.gridDivisions, CONFIG.colors.grid, CONFIG.colors.grid);
409
- gridYZ.rotation.z = Math.PI / 2;
410
- gridYZ.position.set(0, size/2, size/2);
411
- gridYZ.material.transparent = true;
412
- gridYZ.material.opacity = 0.2;
413
- axisGroup.add(gridYZ);
414
-
415
- return axisGroup;
416
- }
417
-
418
- // ============ Create Data Points ============
419
- function createScatterPoints(data) {
420
- const geometry = new THREE.BufferGeometry();
421
- const positions = [];
422
- const colors = [];
423
- const sizes = [];
424
-
425
- const size = CONFIG.axisSize;
426
- const color = new THREE.Color();
427
-
428
- // Normalize data ranges
429
- const timeRange = { min: 0, max: 60 };
430
- const powerRange = { min: 50, max: 400 };
431
- const hrRange = { min: 100, max: 180 };
432
-
433
- data.forEach((point, i) => {
434
- // Map to 3D coordinates
435
- const x = THREE.MathUtils.mapLinear(point.time, timeRange.min, timeRange.max, 0, size);
436
- const y = THREE.MathUtils.mapLinear(point.power, powerRange.min, powerRange.max, 0, size);
437
- const z = THREE.MathUtils.mapLinear(point.hr, hrRange.min, hrRange.max, 0, size);
438
-
439
- positions.push(x, y, z);
440
-
441
- // Color based on power intensity
442
- const powerNorm = (point.power - powerRange.min) / (powerRange.max - powerRange.min);
443
- color.setHSL(
444
- 0.7 - powerNorm * 0.5, // Hue: blue to red
445
- 0.8,
446
- 0.5 + powerNorm * 0.2
447
- );
448
- colors.push(color.r, color.g, color.b);
449
-
450
- // Size based on HR (higher HR = larger point)
451
- const hrNorm = (point.hr - hrRange.min) / (hrRange.max - hrRange.min);
452
- sizes.push(CONFIG.pointSize * (0.8 + hrNorm * 0.4));
453
- });
454
-
455
- geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
456
- geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
457
- geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1));
458
-
459
- // Custom shader material for better looking points
460
- const material = new THREE.ShaderMaterial({
461
- uniforms: {
462
- uPixelRatio: { value: Math.min(window.devicePixelRatio, 2) }
463
- },
464
- vertexShader: `
465
- attribute float size;
466
- attribute vec3 color;
467
- varying vec3 vColor;
468
- uniform float uPixelRatio;
469
-
470
- void main() {
471
- vColor = color;
472
- vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
473
- gl_PointSize = size * uPixelRatio * (300.0 / -mvPosition.z);
474
- gl_Position = projectionMatrix * mvPosition;
475
- }
476
- `,
477
- fragmentShader: `
478
- varying vec3 vColor;
479
-
480
- void main() {
481
- float dist = length(gl_PointCoord - vec2(0.5));
482
- if (dist > 0.5) discard;
483
-
484
- // Soft edge with glow
485
- float alpha = 1.0 - smoothstep(0.3, 0.5, dist);
486
- float glow = exp(-dist * 4.0) * 0.5;
487
-
488
- gl_FragColor = vec4(vColor + glow, alpha);
489
- }
490
- `,
491
- transparent: true,
492
- depthWrite: false,
493
- blending: THREE.AdditiveBlending
494
- });
495
-
496
- return new THREE.Points(geometry, material);
497
- }
498
-
499
- // ============ Create Trail Lines ============
500
- function createTrailLines(data) {
501
- const size = CONFIG.axisSize;
502
- const timeRange = { min: 0, max: 60 };
503
- const powerRange = { min: 50, max: 400 };
504
- const hrRange = { min: 100, max: 180 };
505
-
506
- const points = data.map(point => new THREE.Vector3(
507
- THREE.MathUtils.mapLinear(point.time, timeRange.min, timeRange.max, 0, size),
508
- THREE.MathUtils.mapLinear(point.power, powerRange.min, powerRange.max, 0, size),
509
- THREE.MathUtils.mapLinear(point.hr, hrRange.min, hrRange.max, 0, size)
510
- ));
511
-
512
- const geometry = new THREE.BufferGeometry().setFromPoints(points);
513
- const material = new THREE.LineBasicMaterial({
514
- color: 0x667eea,
515
- transparent: true,
516
- opacity: 0.3,
517
- linewidth: 1
518
- });
519
-
520
- return new THREE.Line(geometry, material);
521
- }
522
-
523
- // ============ Initialize Scene ============
524
- const cyclingData = generateCyclingData(CONFIG.pointCount);
525
-
526
- // Add elements to scene
527
- const axes = createAxes();
528
- scene.add(axes);
529
-
530
- const scatterPoints = createScatterPoints(cyclingData);
531
- scene.add(scatterPoints);
532
-
533
- const trailLine = createTrailLines(cyclingData);
534
- scene.add(trailLine);
535
-
536
- // Ambient light
537
- scene.add(new THREE.AmbientLight(0xffffff, 0.5));
538
-
539
- // ============ Update Stats ============
540
- function updateStats() {
541
- const avgPower = cyclingData.reduce((sum, d) => sum + d.power, 0) / cyclingData.length;
542
- const avgHR = cyclingData.reduce((sum, d) => sum + d.hr, 0) / cyclingData.length;
543
- const duration = cyclingData[cyclingData.length - 1].time;
544
-
545
- document.getElementById('avg-power').textContent = `${Math.round(avgPower)} W`;
546
- document.getElementById('avg-hr').textContent = `${Math.round(avgHR)} bpm`;
547
- document.getElementById('duration').textContent = `${Math.round(duration)} min`;
548
- document.getElementById('points').textContent = cyclingData.length.toLocaleString();
549
- }
550
- updateStats();
551
-
552
- // ============ View Controls ============
553
- const viewPositions = {
554
- perspective: { pos: [12, 10, 12], target: [4, 4, 4] },
555
- top: { pos: [4, 15, 4], target: [4, 0, 4] },
556
- front: { pos: [4, 4, 15], target: [4, 4, 0] },
557
- side: { pos: [15, 4, 4], target: [0, 4, 4] }
558
- };
559
-
560
- let isAutoRotating = false;
561
-
562
- document.querySelectorAll('.control-btn').forEach(btn => {
563
- btn.addEventListener('click', () => {
564
- const view = btn.dataset.view;
565
- const action = btn.dataset.action;
566
-
567
- if (action === 'animate') {
568
- isAutoRotating = !isAutoRotating;
569
- controls.autoRotate = isAutoRotating;
570
- controls.autoRotateSpeed = 1;
571
- btn.classList.toggle('active', isAutoRotating);
572
- return;
573
- }
574
-
575
- if (view && viewPositions[view]) {
576
- const { pos, target } = viewPositions[view];
577
-
578
- // Animate camera transition
579
- const startPos = camera.position.clone();
580
- const startTarget = controls.target.clone();
581
- const endPos = new THREE.Vector3(...pos);
582
- const endTarget = new THREE.Vector3(...target);
583
-
584
- let t = 0;
585
- const animateView = () => {
586
- t += 0.05;
587
- if (t >= 1) {
588
- camera.position.copy(endPos);
589
- controls.target.copy(endTarget);
590
- return;
591
- }
592
-
593
- const easeT = 1 - Math.pow(1 - t, 3); // Ease out cubic
594
- camera.position.lerpVectors(startPos, endPos, easeT);
595
- controls.target.lerpVectors(startTarget, endTarget, easeT);
596
- requestAnimationFrame(animateView);
597
- };
598
- animateView();
599
-
600
- // Update button states
601
- document.querySelectorAll('.control-btn[data-view]').forEach(b => b.classList.remove('active'));
602
- btn.classList.add('active');
603
- }
604
- });
605
- });
606
-
607
- // ============ Animation Loop ============
608
- const clock = new THREE.Clock();
609
-
610
- function animate() {
611
- requestAnimationFrame(animate);
612
-
613
- const elapsed = clock.getElapsedTime();
614
-
615
- // Subtle point animation
616
- const positions = scatterPoints.geometry.attributes.position.array;
617
- const sizes = scatterPoints.geometry.attributes.size.array;
618
-
619
- for (let i = 0; i < sizes.length; i++) {
620
- const baseSize = CONFIG.pointSize * (0.8 + Math.random() * 0.4);
621
- sizes[i] = baseSize * (1 + Math.sin(elapsed * 2 + i * 0.1) * 0.1);
622
- }
623
- scatterPoints.geometry.attributes.size.needsUpdate = true;
624
-
625
- controls.update();
626
- renderer.render(scene, camera);
627
- }
628
- animate();
629
-
630
- // ============ Resize Handler ============
631
- window.addEventListener('resize', () => {
632
- camera.aspect = window.innerWidth / window.innerHeight;
633
- camera.updateProjectionMatrix();
634
- renderer.setSize(window.innerWidth, window.innerHeight);
635
- renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
636
- scatterPoints.material.uniforms.uPixelRatio.value = Math.min(window.devicePixelRatio, 2);
637
- });
638
-
639
- // ============ Raycaster for Hover ============
640
- const raycaster = new THREE.Raycaster();
641
- raycaster.params.Points.threshold = 0.2;
642
- const mouse = new THREE.Vector2();
643
- const tooltip = document.getElementById('tooltip');
644
-
645
- window.addEventListener('mousemove', (event) => {
646
- mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
647
- mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
648
-
649
- raycaster.setFromCamera(mouse, camera);
650
- const intersects = raycaster.intersectObject(scatterPoints);
651
-
652
- if (intersects.length > 0) {
653
- const idx = intersects[0].index;
654
- const point = cyclingData[idx];
655
-
656
- tooltip.innerHTML = `
657
- <div style="color: #667eea; font-weight: 600;">Point #${idx + 1}</div>
658
- <div style="margin-top: 6px;">
659
- <span style="color: #888;">Time:</span>
660
- <span style="color: #48bb78;">${point.time.toFixed(1)} min</span>
661
- </div>
662
- <div>
663
- <span style="color: #888;">Power:</span>
664
- <span style="color: #667eea;">${Math.round(point.power)} W</span>
665
- </div>
666
- <div>
667
- <span style="color: #888;">HR:</span>
668
- <span style="color: #f56565;">${Math.round(point.hr)} bpm</span>
669
- </div>
670
- `;
671
- tooltip.style.left = event.clientX + 15 + 'px';
672
- tooltip.style.top = event.clientY + 15 + 'px';
673
- tooltip.classList.add('visible');
674
- } else {
675
- tooltip.classList.remove('visible');
676
- }
677
- });
678
-
679
- console.log('ApexOS 3D Power Analysis initialized');
680
- console.log(`Rendered ${cyclingData.length} data points`);
681
- </script>
682
- </body>
683
- </html>