ucalyptus commited on
Commit
4851729
·
verified ·
1 Parent(s): 7d08b8b

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +480 -18
  3. prompts.txt +0 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Protocol Viz
3
- emoji: 🦀
4
- colorFrom: yellow
5
- colorTo: pink
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: protocol-viz
3
+ emoji: 🐳
4
+ colorFrom: blue
5
+ colorTo: green
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,481 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
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>Playable In-Ear Device Protocols (B&W)</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://d3js.org/d3.v7.min.js"></script>
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
12
+ <style>
13
+ /* Custom styles */
14
+ body {
15
+ font-family: 'Inter', sans-serif;
16
+ background-color: #f9fafb; /* Light gray background */
17
+ }
18
+ .protocol-container {
19
+ margin-bottom: 1.5rem; /* Space between protocols */
20
+ padding: 1.5rem;
21
+ background-color: white;
22
+ border-radius: 0.5rem; /* Rounded corners */
23
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); /* Subtle shadow */
24
+ position: relative; /* Needed for absolute positioning of progress line */
25
+ }
26
+ .protocol-title {
27
+ font-size: 1.1rem; /* Slightly smaller title */
28
+ font-weight: 600;
29
+ margin-bottom: 1rem;
30
+ color: #1f2937; /* Dark gray text */
31
+ }
32
+ svg {
33
+ display: block;
34
+ margin: auto;
35
+ overflow: visible;
36
+ }
37
+ .bar {
38
+ stroke: #6b7280; /* Medium Gray border for bars */
39
+ stroke-width: 0.5;
40
+ transition: fill 0.1s ease-in-out, stroke-width 0.1s ease-in-out; /* Smooth transition for highlight */
41
+ }
42
+ .bar.active {
43
+ fill: #000000 !important; /* Black for active */
44
+ stroke-width: 1.5;
45
+ stroke: #000000;
46
+ }
47
+ .tooltip {
48
+ position: absolute;
49
+ text-align: center;
50
+ padding: 6px 10px;
51
+ font-size: 12px;
52
+ background: #374151; /* Darker gray background */
53
+ color: white;
54
+ border-radius: 4px;
55
+ pointer-events: none;
56
+ opacity: 0;
57
+ transition: opacity 0.2s;
58
+ white-space: nowrap;
59
+ z-index: 10; /* Ensure tooltip is above elements */
60
+ }
61
+ .axis path,
62
+ .axis line {
63
+ fill: none;
64
+ stroke: #9ca3af; /* Lighter gray axis */
65
+ shape-rendering: crispEdges;
66
+ }
67
+ .axis text {
68
+ font-size: 10px;
69
+ fill: #6b7280; /* Medium gray text for axis */
70
+ }
71
+ .progress-line {
72
+ stroke: #ef4444; /* Red color for progress */
73
+ stroke-width: 1.5;
74
+ pointer-events: none; /* Prevent line from interfering */
75
+ }
76
+ /* Control Buttons Styling */
77
+ .control-button {
78
+ background-color: #3b82f6; /* Blue */
79
+ color: white;
80
+ padding: 0.5rem 1rem;
81
+ border: none;
82
+ border-radius: 0.375rem; /* Rounded */
83
+ font-weight: 600;
84
+ cursor: pointer;
85
+ transition: background-color 0.2s;
86
+ margin: 0 0.25rem; /* Spacing between buttons */
87
+ }
88
+ .control-button:hover {
89
+ background-color: #2563eb; /* Darker Blue */
90
+ }
91
+ .control-button:disabled {
92
+ background-color: #9ca3af; /* Gray when disabled */
93
+ cursor: not-allowed;
94
+ }
95
+ .time-display {
96
+ font-weight: 600;
97
+ color: #1f2937;
98
+ min-width: 100px; /* Ensure space for time */
99
+ text-align: right;
100
+ }
101
+ </style>
102
+ </head>
103
+ <body class="p-6 bg-gray-50">
104
+
105
+ <h1 class="text-2xl font-bold text-center mb-6 text-gray-800">In-Ear Recording Protocols Player</h1>
106
+
107
+ <div class="flex justify-center items-center mb-6 p-4 bg-white rounded-lg shadow">
108
+ <button id="play-pause-button" class="control-button">Play</button>
109
+ <button id="reset-button" class="control-button">Reset</button>
110
+ <div class="ml-4 time-display">
111
+ Time: <span id="current-time">0.0</span>s / <span id="total-duration">0.0</span>s
112
+ </div>
113
+ <input type="range" id="speed-slider" min="0.1" max="5" step="0.1" value="1" class="ml-4 w-32 cursor-pointer">
114
+ <label for="speed-slider" class="ml-2 text-sm text-gray-600">Speed: <span id="speed-value">1.0</span>x</label>
115
+ </div>
116
+
117
+ <div id="jaw-protocol" class="protocol-container">
118
+ <h2 class="protocol-title">Jaw Movements Protocol</h2>
119
+ <svg id="jaw-chart"></svg>
120
+ </div>
121
+ <div id="tongue-protocol" class="protocol-container">
122
+ <h2 class="protocol-title">Tongue Movements Protocol</h2>
123
+ <svg id="tongue-chart"></svg>
124
+ </div>
125
+ <div id="spoken-aloud-protocol" class="protocol-container">
126
+ <h2 class="protocol-title">Spoken Words Protocol (Aloud)</h2>
127
+ <svg id="spoken-aloud-chart"></svg>
128
+ </div>
129
+ <div id="spoken-whisper-protocol" class="protocol-container">
130
+ <h2 class="protocol-title">Spoken Words Protocol (Whisper)</h2>
131
+ <svg id="spoken-whisper-chart"></svg>
132
+ </div>
133
+ <div id="spoken-closed-protocol" class="protocol-container">
134
+ <h2 class="protocol-title">Spoken Words Protocol (Mouth Closed)</h2>
135
+ <svg id="spoken-closed-chart"></svg>
136
+ </div>
137
+ <div id="eyes-protocol" class="protocol-container">
138
+ <h2 class="protocol-title">Eyes Open/Closed Protocol</h2>
139
+ <svg id="eyes-chart"></svg>
140
+ </div>
141
+ <div id="clench-protocol" class="protocol-container">
142
+ <h2 class="protocol-title">Clench Jaw Protocol</h2>
143
+ <svg id="clench-chart"></svg>
144
+ </div>
145
+
146
+ <div id="tooltip" class="tooltip"></div>
147
+
148
+ <script>
149
+ // --- Protocol Data (Keep as is) ---
150
+ const JAW_PROTOCOL = [
151
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
152
+ {"name": "Open jaw", "duration": 2, "color": "#FF9999"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Open jaw", "duration": 2, "color": "#FF9999"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
153
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
154
+ {"name": "Close jaw", "duration": 2, "color": "#99FF99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Close jaw", "duration": 2, "color": "#99FF99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
155
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
156
+ {"name": "Shift to right", "duration": 2, "color": "#9999FF"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Shift to right", "duration": 2, "color": "#9999FF"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
157
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
158
+ {"name": "Shift left", "duration": 2, "color": "#FFCC99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Shift left", "duration": 2, "color": "#FFCC99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
159
+ {"name": "Post-Repetition Rest", "duration": 15, "color": "#CCCCCC"},
160
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
161
+ {"name": "Open jaw", "duration": 2, "color": "#FF9999"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Open jaw", "duration": 2, "color": "#FF9999"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
162
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
163
+ {"name": "Close jaw", "duration": 2, "color": "#99FF99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Close jaw", "duration": 2, "color": "#99FF99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
164
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
165
+ {"name": "Shift to right", "duration": 2, "color": "#9999FF"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Shift to right", "duration": 2, "color": "#9999FF"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
166
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
167
+ {"name": "Shift left", "duration": 2, "color": "#FFCC99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Shift left", "duration": 2, "color": "#FFCC99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
168
+ {"name": "Post-Repetition Rest", "duration": 15, "color": "#CCCCCC"},
169
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
170
+ {"name": "Open jaw", "duration": 2, "color": "#FF9999"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Open jaw", "duration": 2, "color": "#FF9999"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
171
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
172
+ {"name": "Close jaw", "duration": 2, "color": "#99FF99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Close jaw", "duration": 2, "color": "#99FF99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
173
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
174
+ {"name": "Shift to right", "duration": 2, "color": "#9999FF"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Shift to right", "duration": 2, "color": "#9999FF"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"},
175
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"},
176
+ {"name": "Shift left", "duration": 2, "color": "#FFCC99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}, {"name": "Shift left", "duration": 2, "color": "#FFCC99"}, {"name": "Rest", "duration": 1, "color": "#CCCCCC"}
177
+ ];
178
+ const TONGUE_PROTOCOL = [
179
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Tongue Right", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Tongue Left", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Push Upper Teeth", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Push Lower Teeth", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Retraction", "duration": 6, "color": "#CC99FF"}, {"name": "Post-Repetition Rest", "duration": 30, "color": "#CCCCCC"},
180
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Tongue Right", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Tongue Left", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Push Upper Teeth", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Push Lower Teeth", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Retraction", "duration": 6, "color": "#CC99FF"}, {"name": "Post-Repetition Rest", "duration": 30, "color": "#CCCCCC"},
181
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Tongue Right", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Tongue Left", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Push Upper Teeth", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Push Lower Teeth", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Retraction", "duration": 6, "color": "#CC99FF"}
182
+ ];
183
+ const SPOKEN_ALOUD_PROTOCOL = [
184
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Yes'", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'No'", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Reply'", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Call'", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'You'", "duration": 6, "color": "#FF99FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Later'", "duration": 6, "color": "#99CCFF"}, {"name": "Post-Repetition Rest", "duration": 30, "color": "#CCCCCC"},
185
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Yes'", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'No'", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Reply'", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Call'", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'You'", "duration": 6, "color": "#FF99FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Later'", "duration": 6, "color": "#99CCFF"}, {"name": "Post-Repetition Rest", "duration": 30, "color": "#CCCCCC"},
186
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Yes'", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'No'", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Reply'", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Call'", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'You'", "duration": 6, "color": "#FF99FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Say Aloud: 'Later'", "duration": 6, "color": "#99CCFF"}
187
+ ];
188
+ const SPOKEN_WHISPER_PROTOCOL = [
189
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Yes'", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'No'", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Reply'", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Call'", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'You'", "duration": 6, "color": "#FF99FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Later'", "duration": 6, "color": "#99CCFF"}, {"name": "Post-Repetition Rest", "duration": 30, "color": "#CCCCCC"},
190
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Yes'", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'No'", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Reply'", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Call'", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'You'", "duration": 6, "color": "#FF99FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Later'", "duration": 6, "color": "#99CCFF"}, {"name": "Post-Repetition Rest", "duration": 30, "color": "#CCCCCC"},
191
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Yes'", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'No'", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Reply'", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Call'", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'You'", "duration": 6, "color": "#FF99FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Whisper: 'Later'", "duration": 6, "color": "#99CCFF"}
192
+ ];
193
+ const SPOKEN_CLOSED_PROTOCOL = [
194
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Yes'", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'No'", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Reply'", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Call'", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'You'", "duration": 6, "color": "#FF99FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Later'", "duration": 6, "color": "#99CCFF"}, {"name": "Post-Repetition Rest", "duration": 30, "color": "#CCCCCC"},
195
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Yes'", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'No'", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Reply'", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Call'", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'You'", "duration": 6, "color": "#FF99FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Later'", "duration": 6, "color": "#99CCFF"}, {"name": "Post-Repetition Rest", "duration": 30, "color": "#CCCCCC"},
196
+ {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Yes'", "duration": 6, "color": "#FF9999"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'No'", "duration": 6, "color": "#99FF99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Reply'", "duration": 6, "color": "#9999FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Call'", "duration": 6, "color": "#FFCC99"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'You'", "duration": 6, "color": "#FF99FF"}, {"name": "Rest", "duration": 3, "color": "#CCCCCC"}, {"name": "Mouth closed: 'Later'", "duration": 6, "color": "#99CCFF"}
197
+ ];
198
+ const EYES_PROTOCOL = [
199
+ {"name": "Rest", "duration": 5, "color": "#CCCCCC"},
200
+ {"name": "Eyes Closed", "duration": 30, "color": "#FF9999"}, {"name": "Eyes Open", "duration": 30, "color": "#99FF99"},
201
+ {"name": "Eyes Closed", "duration": 30, "color": "#FF9999"}, {"name": "Eyes Open", "duration": 30, "color": "#99FF99"},
202
+ {"name": "Eyes Closed", "duration": 30, "color": "#FF9999"}, {"name": "Eyes Open", "duration": 30, "color": "#99FF99"}
203
+ ];
204
+ const CLENCH_PROTOCOL = [
205
+ {"name": "Rest", "duration": 15, "color": "#99FF99"}, {"name": "Clench", "duration": 15, "color": "#FF9999"},
206
+ {"name": "Rest", "duration": 15, "color": "#99FF99"}, {"name": "Clench", "duration": 15, "color": "#FF9999"},
207
+ {"name": "Rest", "duration": 15, "color": "#99FF99"}, {"name": "Clench", "duration": 15, "color": "#FF9999"}
208
+ ];
209
+
210
+ const ALL_PROTOCOLS = {
211
+ "jaw-chart": JAW_PROTOCOL,
212
+ "tongue-chart": TONGUE_PROTOCOL,
213
+ "spoken-aloud-chart": SPOKEN_ALOUD_PROTOCOL,
214
+ "spoken-whisper-chart": SPOKEN_WHISPER_PROTOCOL,
215
+ "spoken-closed-chart": SPOKEN_CLOSED_PROTOCOL,
216
+ "eyes-chart": EYES_PROTOCOL,
217
+ "clench-chart": CLENCH_PROTOCOL
218
+ };
219
+
220
+ // --- Global State ---
221
+ let timerInterval = null;
222
+ let currentTime = 0; // Current time in seconds
223
+ let isPlaying = false;
224
+ let playbackSpeed = 1.0;
225
+ const timeStep = 0.1; // Update interval in seconds (100ms)
226
+ let maxDuration = 0; // Maximum duration across all protocols
227
+ const scales = {}; // Store scales for each chart
228
+ const processedDataStore = {}; // Store processed data for each chart
229
+
230
+ // --- DOM Elements ---
231
+ const playPauseButton = document.getElementById('play-pause-button');
232
+ const resetButton = document.getElementById('reset-button');
233
+ const currentTimeDisplay = document.getElementById('current-time');
234
+ const totalDurationDisplay = document.getElementById('total-duration');
235
+ const tooltip = d3.select("#tooltip");
236
+ const speedSlider = document.getElementById('speed-slider');
237
+ const speedValueDisplay = document.getElementById('speed-value');
238
+
239
+ // --- Helper Functions ---
240
+ // Function to calculate cumulative duration and add start/end times
241
+ function processProtocolData(protocolData) {
242
+ let cumulativeDuration = 0;
243
+ return protocolData.map(d => {
244
+ const start = cumulativeDuration;
245
+ cumulativeDuration += d.duration;
246
+ return { ...d, start: start, end: cumulativeDuration };
247
+ });
248
+ }
249
+
250
+ // Function to calculate total duration of a processed protocol
251
+ function calculateTotalDuration(processedData) {
252
+ return processedData.length > 0 ? processedData[processedData.length - 1].end : 0;
253
+ }
254
+
255
+ // --- Visualization Function ---
256
+ function createTimeline(chartId, processedData, globalMaxDuration) {
257
+ const container = d3.select(`#${chartId}`);
258
+ if (container.empty()) {
259
+ console.error(`Container element #${chartId} not found.`);
260
+ return;
261
+ }
262
+
263
+ const containerWidth = container.node().getBoundingClientRect().width;
264
+ const margin = { top: 5, right: 15, bottom: 25, left: 15 };
265
+ const width = containerWidth - margin.left - margin.right;
266
+ const height = 60 - margin.top - margin.bottom; // Reduced height
267
+ const barHeight = 25; // Reduced bar height
268
+
269
+ // --- Scales ---
270
+ // Use the global max duration for the domain
271
+ const xScale = d3.scaleLinear()
272
+ .domain([0, globalMaxDuration])
273
+ .range([0, width]);
274
+ scales[chartId] = xScale; // Store the scale
275
+
276
+ // --- SVG Setup ---
277
+ container.selectAll("*").remove(); // Clear previous chart
278
+ const svg = container
279
+ .attr("width", width + margin.left + margin.right)
280
+ .attr("height", height + margin.top + margin.bottom)
281
+ .append("g")
282
+ .attr("transform", `translate(${margin.left},${margin.top})`);
283
+
284
+ // --- Draw Bars ---
285
+ svg.selectAll(".bar")
286
+ .data(processedData)
287
+ .enter()
288
+ .append("rect")
289
+ .attr("class", "bar")
290
+ .attr("data-chart-id", chartId) // Add chart ID for easier selection later
291
+ .attr("x", d => xScale(d.start))
292
+ .attr("y", (height - barHeight) / 2)
293
+ .attr("width", d => Math.max(0, xScale(d.end) - xScale(d.start))) // Ensure width is non-negative
294
+ .attr("height", barHeight)
295
+ .attr("fill", d => d.name.toLowerCase().includes("rest") ? "#D3D3D3" : "#696969") // Initial colors
296
+ .on("mouseover", function(event, d) {
297
+ tooltip.style("opacity", 1);
298
+ })
299
+ .on("mousemove", function(event, d) {
300
+ tooltip.html(`${d.name}<br>Duration: ${d.duration}s<br>Time: ${d.start.toFixed(1)}s - ${d.end.toFixed(1)}s`)
301
+ .style("left", (event.pageX + 10) + "px")
302
+ .style("top", (event.pageY - 28) + "px");
303
+ })
304
+ .on("mouseout", function() {
305
+ tooltip.style("opacity", 0);
306
+ });
307
+
308
+ // --- Add Time Axis ---
309
+ const xAxis = d3.axisBottom(xScale)
310
+ .ticks(Math.min(10, Math.ceil(globalMaxDuration / 15))) // Adjust ticks
311
+ .tickFormat(d => `${d}s`);
312
+
313
+ svg.append("g")
314
+ .attr("class", "axis x-axis")
315
+ .attr("transform", `translate(0,${height})`)
316
+ .call(xAxis);
317
+
318
+ // --- Add Progress Line ---
319
+ svg.append("line")
320
+ .attr("class", "progress-line")
321
+ .attr("x1", xScale(0))
322
+ .attr("x2", xScale(0))
323
+ .attr("y1", -margin.top / 2) // Position slightly above the bars
324
+ .attr("y2", height + margin.bottom / 2) // Extend slightly below axis
325
+ .style("opacity", 0); // Initially hidden
326
+ }
327
+
328
+ // --- Update Highlighting and Progress ---
329
+ function updateVisuals(time) {
330
+ currentTimeDisplay.textContent = time.toFixed(1);
331
+
332
+ // Update highlights for all bars
333
+ d3.selectAll(".bar").each(function(d) {
334
+ const bar = d3.select(this);
335
+ const isActive = time >= d.start && time < d.end;
336
+ bar.classed("active", isActive)
337
+ // Reset fill if not active (needed because !important overrides direct fill)
338
+ .style("fill", isActive ? null : (d.name.toLowerCase().includes("rest") ? "#D3D3D3" : "#696969"));
339
+ });
340
+
341
+ // Update progress lines for all charts
342
+ d3.selectAll(".progress-line").each(function() {
343
+ const line = d3.select(this);
344
+ const chartId = d3.select(this.parentNode).select('.bar').attr('data-chart-id'); // Get chart ID from sibling bar
345
+ if (chartId && scales[chartId]) {
346
+ const xScale = scales[chartId];
347
+ line.attr("x1", xScale(time))
348
+ .attr("x2", xScale(time))
349
+ .style("opacity", 1); // Make visible
350
+ }
351
+ });
352
+ }
353
+
354
+
355
+ // --- Playback Control Functions ---
356
+ function play() {
357
+ if (isPlaying) return;
358
+ isPlaying = true;
359
+ playPauseButton.textContent = 'Pause';
360
+ resetButton.disabled = true; // Disable reset while playing
361
+
362
+ // Clear existing interval if any
363
+ if (timerInterval) clearInterval(timerInterval);
364
+
365
+ let lastTimestamp = performance.now();
366
+
367
+ function tick(currentTimestamp) {
368
+ if (!isPlaying) return; // Stop if paused
369
+
370
+ const elapsedRealTime = (currentTimestamp - lastTimestamp) / 1000; // Time since last frame in seconds
371
+ lastTimestamp = currentTimestamp;
372
+
373
+ currentTime += elapsedRealTime * playbackSpeed; // Increment time based on speed
374
+
375
+ if (currentTime >= maxDuration) {
376
+ currentTime = maxDuration; // Clamp to end
377
+ pause(); // Automatically pause at the end
378
+ resetButton.disabled = false; // Re-enable reset
379
+ }
380
+
381
+ updateVisuals(currentTime);
382
+
383
+ // Continue the loop only if playing
384
+ if (isPlaying) {
385
+ requestAnimationFrame(tick);
386
+ }
387
+ }
388
+ requestAnimationFrame(tick); // Start the loop
389
+ }
390
+
391
+ function pause() {
392
+ if (!isPlaying) return;
393
+ isPlaying = false;
394
+ playPauseButton.textContent = 'Play';
395
+ resetButton.disabled = false; // Re-enable reset
396
+ // No need to clear interval with requestAnimationFrame
397
+ }
398
+
399
+ function reset() {
400
+ pause(); // Ensure it's paused
401
+ currentTime = 0;
402
+ updateVisuals(currentTime);
403
+ d3.selectAll(".progress-line").style("opacity", 0); // Hide progress line on reset
404
+ }
405
+
406
+ // --- Initialization ---
407
+ function initialize() {
408
+ // Process all data and find max duration
409
+ let currentMax = 0;
410
+ for (const chartId in ALL_PROTOCOLS) {
411
+ const processedData = processProtocolData(ALL_PROTOCOLS[chartId]);
412
+ processedDataStore[chartId] = processedData; // Store processed data
413
+ const duration = calculateTotalDuration(processedData);
414
+ if (duration > currentMax) {
415
+ currentMax = duration;
416
+ }
417
+ }
418
+ maxDuration = currentMax;
419
+ totalDurationDisplay.textContent = maxDuration.toFixed(1);
420
+
421
+ // Create all timelines using the global max duration
422
+ for (const chartId in processedDataStore) {
423
+ createTimeline(chartId, processedDataStore[chartId], maxDuration);
424
+ }
425
+
426
+ // Set initial visuals
427
+ updateVisuals(0);
428
+ d3.selectAll(".progress-line").style("opacity", 0); // Ensure lines are hidden initially
429
+
430
+ // Setup Speed Slider
431
+ speedSlider.addEventListener('input', (event) => {
432
+ playbackSpeed = parseFloat(event.target.value);
433
+ speedValueDisplay.textContent = playbackSpeed.toFixed(1);
434
+ });
435
+ speedValueDisplay.textContent = playbackSpeed.toFixed(1); // Initial display
436
+
437
+ // Add event listeners
438
+ playPauseButton.addEventListener('click', () => {
439
+ if (isPlaying) {
440
+ pause();
441
+ } else {
442
+ if (currentTime >= maxDuration) { // If at end, reset before playing
443
+ reset();
444
+ }
445
+ play();
446
+ }
447
+ });
448
+ resetButton.addEventListener('click', reset);
449
+ }
450
+
451
+ // --- Run Initialization on Load ---
452
+ window.addEventListener('load', initialize);
453
+
454
+ // --- Redraw charts on resize ---
455
+ // Debounce resize event for performance
456
+ let resizeTimeout;
457
+ window.addEventListener('resize', () => {
458
+ clearTimeout(resizeTimeout);
459
+ resizeTimeout = setTimeout(() => {
460
+ // Re-initialize everything on resize to recalculate widths/scales
461
+ // Store current state
462
+ const wasPlaying = isPlaying;
463
+ const timeBeforeResize = currentTime;
464
+ // Pause before re-initializing
465
+ pause();
466
+ // Re-initialize
467
+ initialize();
468
+ // Restore state
469
+ currentTime = timeBeforeResize;
470
+ updateVisuals(currentTime);
471
+ if (wasPlaying) {
472
+ play(); // Resume playing if it was playing before
473
+ }
474
+
475
+ }, 250); // Wait 250ms after last resize event
476
+ });
477
+
478
+ </script>
479
+
480
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=ucalyptus/protocol-viz" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
481
  </html>
prompts.txt ADDED
File without changes