sumulige-claude 1.5.1 → 1.5.2

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 (219) 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/cli.js +1 -1
  48. package/package.json +25 -3
  49. package/.claude/.kickoff-hint.txt +0 -52
  50. package/.claude/.sumulige-claude-version +0 -1
  51. package/.claude/.version +0 -1
  52. package/.claude/AGENTS.md +0 -42
  53. package/.claude/ANCHORS.md +0 -40
  54. package/.claude/CLAUDE.md +0 -138
  55. package/.claude/MEMORY.md +0 -69
  56. package/.claude/PROJECT_LOG.md +0 -101
  57. package/.claude/THINKING_CHAIN_GUIDE.md +0 -287
  58. package/.claude/USAGE.md +0 -175
  59. package/.claude/boris-optimizations.md +0 -167
  60. package/.claude/handoffs/INDEX.md +0 -21
  61. package/.claude/handoffs/LATEST.md +0 -76
  62. package/.claude/handoffs/handoff_2026-01-22T13-07-04-757Z.md +0 -76
  63. package/.claude/quality-gate.json +0 -82
  64. package/.claude/rag/skill-index.json +0 -135
  65. package/.claude/settings.json +0 -99
  66. package/.claude/settings.local.json +0 -175
  67. package/.claude/templates/PROJECT_KICKOFF.md +0 -89
  68. package/.claude/templates/PROJECT_PROPOSAL.md +0 -227
  69. package/.claude/templates/TASK_PLAN.md +0 -121
  70. package/.claude/templates/hooks/README.md +0 -302
  71. package/.claude/templates/hooks/hook.sh.template +0 -94
  72. package/.claude/templates/hooks/user-prompt-submit.cjs.template +0 -116
  73. package/.claude/templates/hooks/user-response-submit.cjs.template +0 -94
  74. package/.claude/templates/hooks/validate.js +0 -173
  75. package/.claude/templates/tasks/develop.md +0 -69
  76. package/.claude/templates/tasks/research.md +0 -64
  77. package/.claude/templates/tasks/test.md +0 -96
  78. package/.claude/thinking-routes/.last-sync +0 -1
  79. package/.claude/thinking-routes/QUICKREF.md +0 -98
  80. package/.claude/workflow/document-scanner.js +0 -426
  81. package/.claude/workflow/knowledge-engine.js +0 -941
  82. package/.claude/workflow/notebooklm/browser.js +0 -1028
  83. package/.claude/workflow/phases/phase1-research.js +0 -578
  84. package/.claude/workflow/phases/phase1-research.ts +0 -465
  85. package/.claude/workflow/phases/phase2-approve.js +0 -722
  86. package/.claude/workflow/phases/phase3-plan.js +0 -1200
  87. package/.claude/workflow/phases/phase4-develop.js +0 -894
  88. package/.claude/workflow/search-cache.js +0 -230
  89. package/.claude/workflow/templates/approval.md +0 -315
  90. package/.claude/workflow/templates/development.md +0 -377
  91. package/.claude/workflow/templates/planning.md +0 -328
  92. package/.claude/workflow/templates/research.md +0 -250
  93. package/.claude/workflow/types.js +0 -37
  94. package/.claude/workflow/web-search.js +0 -278
  95. package/.claude-plugin/marketplace.json +0 -71
  96. package/.github/workflows/sync-skills.yml +0 -74
  97. package/.versionrc +0 -25
  98. package/AGENTS.md +0 -580
  99. package/CHANGELOG.md +0 -481
  100. package/CLAUDE-template.md +0 -114
  101. package/DEV_TOOLS_GUIDE.md +0 -190
  102. package/PROJECT_STRUCTURE.md +0 -266
  103. package/Q&A.md +0 -325
  104. package/config/defaults.json +0 -34
  105. package/config/official-skills.json +0 -183
  106. package/config/quality-gate.json +0 -67
  107. package/config/skill-categories.json +0 -40
  108. package/config/version-manifest.json +0 -85
  109. package/demos/power-3d-scatter.html +0 -683
  110. package/development/cache/web-search/search_1193d605f8eb364651fc2f2041b58a31.json +0 -36
  111. package/development/cache/web-search/search_3798bf06960edc125f744a1abb5b72c5.json +0 -36
  112. package/development/cache/web-search/search_37c7d4843a53f0d83f1122a6f908a2a3.json +0 -36
  113. package/development/cache/web-search/search_44166fa0153709ee168485a22aa0ab40.json +0 -36
  114. package/development/cache/web-search/search_4deaebb1f77e86a8ca066dc5a49c59fd.json +0 -36
  115. package/development/cache/web-search/search_94da91789466070a7f545612e73c7372.json +0 -36
  116. package/development/cache/web-search/search_dd5de8491b8b803a3cb01339cd210fb0.json +0 -36
  117. package/development/knowledge-base/.index.clean.json +0 -1
  118. package/development/knowledge-base/.index.json +0 -486
  119. package/development/knowledge-base/test-best-practices.md +0 -29
  120. package/development/projects/proj_mkh1pazz_ixmt1/phase1/feasibility-report.md +0 -160
  121. package/development/projects/proj_mkh4jvnb_z7rwf/phase1/feasibility-report.md +0 -160
  122. package/development/projects/proj_mkh4jxkd_ewz5a/phase1/feasibility-report.md +0 -160
  123. package/development/projects/proj_mkh4k84n_ni73k/phase1/feasibility-report.md +0 -160
  124. package/development/projects/proj_mkh4wfyd_u9w88/phase1/feasibility-report.md +0 -160
  125. package/development/projects/proj_mkh4wsbo_iahvf/development/projects/proj_mkh4xbpg_4na5w/phase1/feasibility-report.md +0 -160
  126. package/development/projects/proj_mkh4wsbo_iahvf/phase1/feasibility-report.md +0 -160
  127. package/development/projects/proj_mkh4xulg_1ka8x/phase1/feasibility-report.md +0 -160
  128. package/development/projects/proj_mkh4xwhj_gch8j/phase1/feasibility-report.md +0 -160
  129. package/development/projects/proj_mkh4y2qk_9lm8z/phase1/feasibility-report.md +0 -160
  130. package/development/projects/proj_mkh4y2qk_9lm8z/phase2/requirements.md +0 -226
  131. package/development/projects/proj_mkh4y2qk_9lm8z/phase3/PRD.md +0 -345
  132. package/development/projects/proj_mkh4y2qk_9lm8z/phase3/TASK_PLAN.md +0 -284
  133. package/development/projects/proj_mkh4y2qk_9lm8z/phase3/prototype/README.md +0 -14
  134. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/DEVELOPMENT_LOG.md +0 -35
  135. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/TASKS.md +0 -34
  136. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/.env.example +0 -5
  137. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/README.md +0 -60
  138. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/package.json +0 -25
  139. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/index.js +0 -70
  140. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/routes/index.js +0 -48
  141. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/health.test.js +0 -20
  142. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/jest.config.js +0 -21
  143. package/development/projects/proj_mkh7veqg_3lypc/phase1/feasibility-report.md +0 -160
  144. package/development/projects/proj_mkh7veqg_3lypc/phase2/requirements.md +0 -226
  145. package/development/projects/proj_mkh7veqg_3lypc/phase3/PRD.md +0 -345
  146. package/development/projects/proj_mkh7veqg_3lypc/phase3/TASK_PLAN.md +0 -284
  147. package/development/projects/proj_mkh7veqg_3lypc/phase3/prototype/README.md +0 -14
  148. package/development/projects/proj_mkh8k8fo_rmqn5/phase1/feasibility-report.md +0 -160
  149. package/development/projects/proj_mkh8xyhy_1vshq/phase1/feasibility-report.md +0 -178
  150. package/development/projects/proj_mkh8zddd_dhamf/phase1/feasibility-report.md +0 -377
  151. package/development/projects/proj_mkh8zddd_dhamf/phase2/requirements.md +0 -442
  152. package/development/projects/proj_mkh8zddd_dhamf/phase3/api-design.md +0 -800
  153. package/development/projects/proj_mkh8zddd_dhamf/phase3/architecture.md +0 -625
  154. package/development/projects/proj_mkh8zddd_dhamf/phase3/data-model.md +0 -830
  155. package/development/projects/proj_mkh8zddd_dhamf/phase3/risks.md +0 -957
  156. package/development/projects/proj_mkh8zddd_dhamf/phase3/wbs.md +0 -381
  157. package/development/todos/.state.json +0 -19
  158. package/development/todos/INDEX.md +0 -63
  159. package/development/todos/active/_README.md +0 -49
  160. package/development/todos/archived/_README.md +0 -11
  161. package/development/todos/backlog/_README.md +0 -11
  162. package/development/todos/backlog/mcp-integration.md +0 -35
  163. package/development/todos/completed/_README.md +0 -11
  164. package/development/todos/completed/boris-optimizations.md +0 -39
  165. package/development/todos/completed/develop/local-knowledge-index.md +0 -85
  166. package/development/todos/completed/develop/todo-system.md +0 -47
  167. package/development/todos/completed/develop/web-search-integration.md +0 -83
  168. package/development/todos/completed/test/phase1-e2e-test.md +0 -103
  169. package/docs/DEVELOPMENT.md +0 -461
  170. package/docs/MARKETPLACE.md +0 -352
  171. package/docs/RELEASE.md +0 -93
  172. package/jest.config.js +0 -63
  173. package/lib/commands.js +0 -3588
  174. package/lib/config-manager.js +0 -441
  175. package/lib/config-schema.js +0 -408
  176. package/lib/config-validator.js +0 -330
  177. package/lib/config.js +0 -122
  178. package/lib/errors.js +0 -305
  179. package/lib/incremental-sync.js +0 -274
  180. package/lib/marketplace.js +0 -487
  181. package/lib/migrations.js +0 -154
  182. package/lib/permission-audit.js +0 -255
  183. package/lib/quality-gate.js +0 -431
  184. package/lib/quality-rules.js +0 -373
  185. package/lib/utils.js +0 -150
  186. package/lib/version-check.js +0 -169
  187. package/lib/version-manifest.js +0 -171
  188. package/project-paradigm.md +0 -313
  189. package/prompts/how-to-find.md +0 -163
  190. package/prompts/linus-architect.md +0 -71
  191. package/prompts/software-architect.md +0 -173
  192. package/prompts/web-designer.md +0 -249
  193. package/scripts/fix-hooks.mjs +0 -97
  194. package/scripts/sync-external.mjs +0 -298
  195. package/scripts/sync-to-home.sh +0 -108
  196. package/scripts/update-registry.mjs +0 -325
  197. package/sources.yaml +0 -83
  198. package/tests/README.md +0 -263
  199. package/tests/commands.test.js +0 -1086
  200. package/tests/config-manager.test.js +0 -677
  201. package/tests/config-schema.test.js +0 -425
  202. package/tests/config-validator.test.js +0 -436
  203. package/tests/config.test.js +0 -100
  204. package/tests/errors.test.js +0 -477
  205. package/tests/manual/phase1-e2e.sh +0 -389
  206. package/tests/manual/phase2-test-cases.md +0 -311
  207. package/tests/manual/phase3-test-cases.md +0 -309
  208. package/tests/manual/phase4-test-cases.md +0 -414
  209. package/tests/manual/test-cases.md +0 -417
  210. package/tests/marketplace.test.js +0 -420
  211. package/tests/migrations.test.js +0 -187
  212. package/tests/quality-gate.test.js +0 -679
  213. package/tests/quality-rules.test.js +0 -619
  214. package/tests/sync-external.test.js +0 -214
  215. package/tests/update-registry.test.js +0 -251
  216. package/tests/utils.test.js +0 -171
  217. package/tests/version-check.test.js +0 -75
  218. package/tests/web-search.test.js +0 -392
  219. 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>