@nebularstreams/overlay-sdk 1.0.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 (133) hide show
  1. package/package.json +44 -0
  2. package/preview/assets/images/favicon.ico +0 -0
  3. package/preview/assets/images/favicon.png +0 -0
  4. package/preview/assets/images/login-right.webp +0 -0
  5. package/preview/assets/images/nebular.color.100h.png +0 -0
  6. package/preview/assets/images/nebular.color.white.100h.png +0 -0
  7. package/preview/assets/images/nebular.medallion.transparent..png +0 -0
  8. package/preview/assets/images/testcard.png +0 -0
  9. package/preview/assets/webfonts/fa-brands-400.woff2 +0 -0
  10. package/preview/assets/webfonts/fa-solid-900.woff2 +0 -0
  11. package/preview/bundle.min.js +6 -0
  12. package/preview/index.css +28 -0
  13. package/preview/index.html +23 -0
  14. package/readme.md +132 -0
  15. package/skill/nebular-overlay/SKILL.md +56 -0
  16. package/skill/nebular-overlay/agents/openai.yaml +4 -0
  17. package/skill/nebular-overlay/references/examples.md +327 -0
  18. package/skill/nebular-overlay/references/manifest.md +153 -0
  19. package/skill/nebular-overlay/references/runtime-and-design.md +88 -0
  20. package/skill/nebular-overlay/scripts/validate-templates.mjs +244 -0
  21. package/templates/all/broadcast/breaking-news/index.html +100 -0
  22. package/templates/all/broadcast/breaking-news/manifest.json +9 -0
  23. package/templates/all/broadcast/empty/index.html +46 -0
  24. package/templates/all/broadcast/empty/manifest.json +7 -0
  25. package/templates/all/broadcast/empty/nebular.medallion.transparent.png +0 -0
  26. package/templates/all/broadcast/event-countdown/index.html +160 -0
  27. package/templates/all/broadcast/event-countdown/logo.png +0 -0
  28. package/templates/all/broadcast/event-countdown/manifest.json +33 -0
  29. package/templates/all/broadcast/lower-third/index.html +77 -0
  30. package/templates/all/broadcast/lower-third/manifest.json +8 -0
  31. package/templates/all/broadcast/newsticker/index.html +153 -0
  32. package/templates/all/broadcast/newsticker/manifest.json +21 -0
  33. package/templates/all/broadcast/newsticker-frames/background-label-green.png +0 -0
  34. package/templates/all/broadcast/newsticker-frames/background-label-orange.png +0 -0
  35. package/templates/all/broadcast/newsticker-frames/banner.png +0 -0
  36. package/templates/all/broadcast/newsticker-frames/index.html +229 -0
  37. package/templates/all/broadcast/newsticker-frames/manifest.json +20 -0
  38. package/templates/all/broadcast/weather/index.html +382 -0
  39. package/templates/all/broadcast/weather/manifest.json +104 -0
  40. package/templates/all/engagement/call-to-action/index.html +116 -0
  41. package/templates/all/engagement/call-to-action/manifest.json +12 -0
  42. package/templates/all/engagement/chat/index.html +121 -0
  43. package/templates/all/engagement/chat/manifest.json +32 -0
  44. package/templates/all/engagement/post/index.html +132 -0
  45. package/templates/all/engagement/post/manifest.json +31 -0
  46. package/templates/all/gambling/bingo/index.html +227 -0
  47. package/templates/all/gambling/bingo/manifest.json +144 -0
  48. package/templates/all/gambling/keno/index.html +202 -0
  49. package/templates/all/gambling/keno/manifest.json +129 -0
  50. package/templates/all/gambling/lottery/index.html +159 -0
  51. package/templates/all/gambling/lottery/manifest.json +95 -0
  52. package/templates/all/gambling/prize-wall/index.html +256 -0
  53. package/templates/all/gambling/prize-wall/manifest.json +108 -0
  54. package/templates/all/gambling/roulette/index.html +200 -0
  55. package/templates/all/gambling/roulette/manifest.json +78 -0
  56. package/templates/all/gaming/battleship/index.html +578 -0
  57. package/templates/all/gaming/battleship/manifest.json +279 -0
  58. package/templates/all/gaming/gta/mission/index.html +121 -0
  59. package/templates/all/gaming/gta/mission/manifest.json +38 -0
  60. package/templates/all/sports/football/scoreboard/index.html +115 -0
  61. package/templates/all/sports/football/scoreboard/manifest.json +54 -0
  62. package/templates/all/sports/tennis/scoreboard/index.html +120 -0
  63. package/templates/all/sports/tennis/scoreboard/manifest.json +92 -0
  64. package/templates/all/trivia/audience-poll/index.html +60 -0
  65. package/templates/all/trivia/audience-poll/manifest.json +26 -0
  66. package/templates/all/trivia/classic-quiz/index.html +49 -0
  67. package/templates/all/trivia/classic-quiz/manifest.json +15 -0
  68. package/templates/all/trivia/lightning-round/index.html +126 -0
  69. package/templates/all/trivia/lightning-round/manifest.json +27 -0
  70. package/templates/all/trivia/pasapalabra/index.html +249 -0
  71. package/templates/all/trivia/pasapalabra/manifest.json +68 -0
  72. package/templates/all/trivia/quiz-deck/index.html +58 -0
  73. package/templates/all/trivia/quiz-deck/manifest.json +25 -0
  74. package/templates/all/trivia/true-or-false/index.html +81 -0
  75. package/templates/all/trivia/true-or-false/manifest.json +27 -0
  76. package/templates/basic/broadcast/empty/index.html +46 -0
  77. package/templates/basic/broadcast/empty/manifest.json +7 -0
  78. package/templates/basic/broadcast/empty/nebular.medallion.transparent.png +0 -0
  79. package/templates/basic/broadcast/event-countdown/index.html +160 -0
  80. package/templates/basic/broadcast/event-countdown/logo.png +0 -0
  81. package/templates/basic/broadcast/event-countdown/manifest.json +33 -0
  82. package/templates/basic/broadcast/lower-third/index.html +77 -0
  83. package/templates/basic/broadcast/lower-third/manifest.json +8 -0
  84. package/templates/basic/broadcast/newsticker/index.html +153 -0
  85. package/templates/basic/broadcast/newsticker/manifest.json +21 -0
  86. package/templates/basic/broadcast/weather/index.html +382 -0
  87. package/templates/basic/broadcast/weather/manifest.json +104 -0
  88. package/templates/basic/engagement/call-to-action/index.html +116 -0
  89. package/templates/basic/engagement/call-to-action/manifest.json +12 -0
  90. package/templates/basic/engagement/chat/index.html +121 -0
  91. package/templates/basic/engagement/chat/manifest.json +32 -0
  92. package/templates/basic/engagement/post/index.html +132 -0
  93. package/templates/basic/engagement/post/manifest.json +31 -0
  94. package/templates/basic/sports/football/scoreboard/index.html +115 -0
  95. package/templates/basic/sports/football/scoreboard/manifest.json +54 -0
  96. package/templates/basic/sports/tennis/scoreboard/index.html +120 -0
  97. package/templates/basic/sports/tennis/scoreboard/manifest.json +92 -0
  98. package/templates/debug/testing/security-probe/forbidden.js +1 -0
  99. package/templates/debug/testing/security-probe/forbidden.json +1 -0
  100. package/templates/debug/testing/security-probe/forbidden.mp4 +1 -0
  101. package/templates/debug/testing/security-probe/forbidden.svg +1 -0
  102. package/templates/debug/testing/security-probe/index.html +367 -0
  103. package/templates/debug/testing/security-probe/manifest.json +13 -0
  104. package/templates/empty/broadcast/empty/index.html +46 -0
  105. package/templates/empty/broadcast/empty/manifest.json +7 -0
  106. package/templates/empty/broadcast/empty/nebular.medallion.transparent.png +0 -0
  107. package/templates/games/gambling/bingo/index.html +227 -0
  108. package/templates/games/gambling/bingo/manifest.json +56 -0
  109. package/templates/games/gambling/keno/index.html +202 -0
  110. package/templates/games/gambling/keno/manifest.json +129 -0
  111. package/templates/games/gambling/lottery/index.html +159 -0
  112. package/templates/games/gambling/lottery/manifest.json +95 -0
  113. package/templates/games/gambling/prize-wall/index.html +256 -0
  114. package/templates/games/gambling/prize-wall/manifest.json +108 -0
  115. package/templates/games/gambling/roulette/index.html +200 -0
  116. package/templates/games/gambling/roulette/manifest.json +78 -0
  117. package/templates/games/gaming/battleship/index.html +578 -0
  118. package/templates/games/gaming/battleship/manifest.json +279 -0
  119. package/templates/games/gaming/gta/mission/index.html +121 -0
  120. package/templates/games/gaming/gta/mission/manifest.json +38 -0
  121. package/templates/games/trivia/audience-poll/index.html +60 -0
  122. package/templates/games/trivia/audience-poll/manifest.json +26 -0
  123. package/templates/games/trivia/classic-quiz/index.html +49 -0
  124. package/templates/games/trivia/classic-quiz/manifest.json +15 -0
  125. package/templates/games/trivia/lightning-round/index.html +126 -0
  126. package/templates/games/trivia/lightning-round/manifest.json +27 -0
  127. package/templates/games/trivia/pasapalabra/index.html +249 -0
  128. package/templates/games/trivia/pasapalabra/manifest.json +68 -0
  129. package/templates/games/trivia/quiz-deck/index.html +58 -0
  130. package/templates/games/trivia/quiz-deck/manifest.json +25 -0
  131. package/templates/games/trivia/true-or-false/index.html +81 -0
  132. package/templates/games/trivia/true-or-false/manifest.json +27 -0
  133. package/tool/cli.cjs +7 -0
@@ -0,0 +1,279 @@
1
+ {
2
+ "instructions": "Place the fleet by selecting every coordinate occupied by a ship; adjoining cells form one vessel, so leave water between separate boats. Keep Fleet display hidden during play, then add every coordinate fired upon by the player. The overlay determines hits, misses and sunk vessels automatically. Reveal the fleet when the round ends. Use Reset round to clear all shots and hide the fleet again, then press Update.",
3
+ "meta": {
4
+ "content/title": {
5
+ "type": "string",
6
+ "phase": "edit",
7
+ "label": "Title", "hint": "Enter title",
8
+ "default": "Fleet Command"
9
+ },
10
+ "content/player": {
11
+ "type": "string",
12
+ "phase": "edit",
13
+ "label": "Player", "hint": "Enter player name",
14
+ "default": "John Carter"
15
+ },
16
+ "content/location": {
17
+ "type": "string",
18
+ "phase": "edit",
19
+ "label": "Player location", "hint": "Enter player location",
20
+ "default": "New York · NY"
21
+ },
22
+ "board/fleet": {
23
+ "type": "multi",
24
+ "phase": "edit",
25
+ "container": "big",
26
+ "label": "Fleet positions", "hint": "Every coordinate occupied by the player's ships",
27
+ "choose": [
28
+ "A1",
29
+ "A2",
30
+ "A3",
31
+ "A4",
32
+ "A5",
33
+ "A6",
34
+ "A7",
35
+ "A8",
36
+ "A9",
37
+ "A10",
38
+ "B1",
39
+ "B2",
40
+ "B3",
41
+ "B4",
42
+ "B5",
43
+ "B6",
44
+ "B7",
45
+ "B8",
46
+ "B9",
47
+ "B10",
48
+ "C1",
49
+ "C2",
50
+ "C3",
51
+ "C4",
52
+ "C5",
53
+ "C6",
54
+ "C7",
55
+ "C8",
56
+ "C9",
57
+ "C10",
58
+ "D1",
59
+ "D2",
60
+ "D3",
61
+ "D4",
62
+ "D5",
63
+ "D6",
64
+ "D7",
65
+ "D8",
66
+ "D9",
67
+ "D10",
68
+ "E1",
69
+ "E2",
70
+ "E3",
71
+ "E4",
72
+ "E5",
73
+ "E6",
74
+ "E7",
75
+ "E8",
76
+ "E9",
77
+ "E10",
78
+ "F1",
79
+ "F2",
80
+ "F3",
81
+ "F4",
82
+ "F5",
83
+ "F6",
84
+ "F7",
85
+ "F8",
86
+ "F9",
87
+ "F10",
88
+ "G1",
89
+ "G2",
90
+ "G3",
91
+ "G4",
92
+ "G5",
93
+ "G6",
94
+ "G7",
95
+ "G8",
96
+ "G9",
97
+ "G10",
98
+ "H1",
99
+ "H2",
100
+ "H3",
101
+ "H4",
102
+ "H5",
103
+ "H6",
104
+ "H7",
105
+ "H8",
106
+ "H9",
107
+ "H10",
108
+ "I1",
109
+ "I2",
110
+ "I3",
111
+ "I4",
112
+ "I5",
113
+ "I6",
114
+ "I7",
115
+ "I8",
116
+ "I9",
117
+ "I10",
118
+ "J1",
119
+ "J2",
120
+ "J3",
121
+ "J4",
122
+ "J5",
123
+ "J6",
124
+ "J7",
125
+ "J8",
126
+ "J9",
127
+ "J10"
128
+ ],
129
+ "cols": 10,
130
+ "rows": 10,
131
+ "responsive": true,
132
+ "minCellWidth": "2.54rem",
133
+ "default": [
134
+ "A2", "A3", "A4", "A5",
135
+ "C3", "C4", "C5",
136
+ "F7", "F8", "F9",
137
+ "H2", "H3",
138
+ "J8", "J9"
139
+ ]
140
+ },
141
+ "content/playPlayer": {
142
+ "type": "string",
143
+ "phase": "play",
144
+ "label": "Player", "hint": "Player name displayed during the round",
145
+ "source": "content/player",
146
+ "readonly": true
147
+ },
148
+ "board/fleetVisibility": {
149
+ "type": "choose",
150
+ "phase": "play",
151
+ "label": "Fleet display", "hint": "Hide the fleet during play or reveal it after the round",
152
+ "choose": ["hidden", "revealed"],
153
+ "default": "hidden"
154
+ },
155
+ "board/shots": {
156
+ "type": "multi",
157
+ "phase": "play",
158
+ "container": "big",
159
+ "label": "Player shots", "hint": "Coordinates fired upon by the player",
160
+ "choose": [
161
+ "A1",
162
+ "A2",
163
+ "A3",
164
+ "A4",
165
+ "A5",
166
+ "A6",
167
+ "A7",
168
+ "A8",
169
+ "A9",
170
+ "A10",
171
+ "B1",
172
+ "B2",
173
+ "B3",
174
+ "B4",
175
+ "B5",
176
+ "B6",
177
+ "B7",
178
+ "B8",
179
+ "B9",
180
+ "B10",
181
+ "C1",
182
+ "C2",
183
+ "C3",
184
+ "C4",
185
+ "C5",
186
+ "C6",
187
+ "C7",
188
+ "C8",
189
+ "C9",
190
+ "C10",
191
+ "D1",
192
+ "D2",
193
+ "D3",
194
+ "D4",
195
+ "D5",
196
+ "D6",
197
+ "D7",
198
+ "D8",
199
+ "D9",
200
+ "D10",
201
+ "E1",
202
+ "E2",
203
+ "E3",
204
+ "E4",
205
+ "E5",
206
+ "E6",
207
+ "E7",
208
+ "E8",
209
+ "E9",
210
+ "E10",
211
+ "F1",
212
+ "F2",
213
+ "F3",
214
+ "F4",
215
+ "F5",
216
+ "F6",
217
+ "F7",
218
+ "F8",
219
+ "F9",
220
+ "F10",
221
+ "G1",
222
+ "G2",
223
+ "G3",
224
+ "G4",
225
+ "G5",
226
+ "G6",
227
+ "G7",
228
+ "G8",
229
+ "G9",
230
+ "G10",
231
+ "H1",
232
+ "H2",
233
+ "H3",
234
+ "H4",
235
+ "H5",
236
+ "H6",
237
+ "H7",
238
+ "H8",
239
+ "H9",
240
+ "H10",
241
+ "I1",
242
+ "I2",
243
+ "I3",
244
+ "I4",
245
+ "I5",
246
+ "I6",
247
+ "I7",
248
+ "I8",
249
+ "I9",
250
+ "I10",
251
+ "J1",
252
+ "J2",
253
+ "J3",
254
+ "J4",
255
+ "J5",
256
+ "J6",
257
+ "J7",
258
+ "J8",
259
+ "J9",
260
+ "J10"
261
+ ],
262
+ "cols": 10,
263
+ "rows": 10,
264
+ "responsive": true,
265
+ "minCellWidth": "2.54rem",
266
+ "default": ["A3", "B8", "D4", "F8", "H9", "J8"]
267
+ },
268
+ "board/reset": {
269
+ "type": "reset",
270
+ "phase": "play",
271
+ "icon": "undo",
272
+ "text": "Reset round", "hint": "Clear all shots and hide the fleet for a new round",
273
+ "values": {
274
+ "board/fleetVisibility": "hidden",
275
+ "board/shots": []
276
+ }
277
+ }
278
+ }
279
+ }
@@ -0,0 +1,121 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>GTA Mission Panel</title>
6
+ <style>
7
+ * {
8
+ box-sizing: border-box;
9
+ }
10
+
11
+ html, body {
12
+ width: 100%;
13
+ height: 100%;
14
+ margin: 0;
15
+ overflow: hidden;
16
+ background: transparent;
17
+ }
18
+
19
+ body {
20
+ color: #fff;
21
+ font-family: Impact, Haettenschweiler, "Arial Narrow Bold", sans-serif;
22
+ letter-spacing: .035em;
23
+ }
24
+
25
+ .mission {
26
+ position: absolute;
27
+ right: 5%;
28
+ top: 9%;
29
+ width: 34rem;
30
+ padding: 1.6rem 1.8rem;
31
+ background: rgba(8, 8, 8, .88);
32
+ border-left: .55rem solid #78d84b;
33
+ box-shadow: 0 1rem 3rem #0008;
34
+ transform: skewX(-2deg);
35
+ }
36
+
37
+ .eyebrow {
38
+ color: #78d84b;
39
+ font: 700 .8rem system-ui, sans-serif;
40
+ letter-spacing: .22em;
41
+ text-transform: uppercase;
42
+ }
43
+
44
+ h1 {
45
+ margin: .25rem 0 .5rem;
46
+ font-size: 2.6rem;
47
+ text-transform: uppercase;
48
+ text-shadow: .16rem .16rem 0 #000;
49
+ }
50
+
51
+ .objective {
52
+ margin: 0 0 1.2rem;
53
+ color: #ddd;
54
+ font: 600 1rem system-ui, sans-serif;
55
+ letter-spacing: normal;
56
+ }
57
+
58
+ .footer {
59
+ display: flex;
60
+ justify-content: space-between;
61
+ align-items: center;
62
+ gap: 1rem;
63
+ }
64
+
65
+ .progress {
66
+ flex: 1;
67
+ height: .7rem;
68
+ overflow: hidden;
69
+ background: #333;
70
+ }
71
+
72
+ .progress span {
73
+ display: block;
74
+ width: 65%;
75
+ height: 100%;
76
+ background: #78d84b;
77
+ transition: width .35s ease;
78
+ }
79
+
80
+ .reward {
81
+ color: #8fea62;
82
+ font-size: 1.45rem;
83
+ white-space: nowrap;
84
+ }
85
+ </style>
86
+ </head>
87
+ <body>
88
+ <section class="mission">
89
+ <div class="eyebrow">Current objective</div>
90
+ <h1 id="mission">THE GETAWAY</h1>
91
+ <p class="objective" id="objective">Reach the safehouse</p>
92
+ <div class="footer">
93
+ <div class="progress"><span id="progress"></span></div>
94
+ <div class="reward" id="reward">$5,000</div>
95
+ </div>
96
+ </section>
97
+ <script>
98
+
99
+ // convenience to assign values
100
+ const $ = (name, value) => {
101
+ const element = document.getElementById(name);
102
+ if (element) {
103
+ if (value !== undefined) element.textContent = String(value);
104
+ else return element;
105
+ }
106
+ }
107
+
108
+ function setProgress(value) {
109
+ const percentage = Math.max(0, Math.min(100, Number(value)));
110
+ $("progress").style.width = `${percentage}%`;
111
+ }
112
+
113
+ window.addEventListener("nebular-overlay:update", ({detail}) => {
114
+ if (detail.mission?.title != null) $("mission", detail.mission.title);
115
+ if (detail.mission?.objective != null) $("objective", detail.mission.objective);
116
+ if (detail.mission?.reward != null) $("reward", detail.mission.reward);
117
+ if (detail.mission?.progress != null) setProgress(detail.mission.progress);
118
+ });
119
+ </script>
120
+ </body>
121
+ </html>
@@ -0,0 +1,38 @@
1
+ {
2
+ "instructions": "Enter the mission title, objective and reward, then adjust progress as the mission advances. Press Update to refresh the mission panel without changing unrelated fields.",
3
+ "meta": {
4
+ "mission/title": {
5
+ "type": "string",
6
+ "phase": "edit",
7
+ "label": "Mission title", "hint": "Enter mission title",
8
+ "default": "THE GETAWAY"
9
+ },
10
+ "mission/objective": {
11
+ "type": "string",
12
+ "phase": "edit",
13
+ "label": "Objective", "hint": "Enter objective",
14
+ "default": "Reach the safehouse"
15
+ },
16
+ "mission/reward": {
17
+ "type": "string",
18
+ "phase": "edit",
19
+ "label": "Reward", "hint": "Enter reward",
20
+ "default": "$5,000"
21
+ },
22
+ "mission/playObjective": {
23
+ "type": "string",
24
+ "phase": "play",
25
+ "label": "Objective", "hint": "Mission objective displayed during play",
26
+ "source": "mission/objective",
27
+ "readonly": true
28
+ },
29
+ "mission/progress": {
30
+ "type": "range",
31
+ "phase": "play",
32
+ "label": "Progress", "hint": "Current completion percentage for the mission",
33
+ "min": 0,
34
+ "max": 100,
35
+ "default": 65
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,115 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Football Scoreboard</title>
6
+ <style>
7
+ * {
8
+ box-sizing: border-box;
9
+ }
10
+
11
+ html, body {
12
+ width: 100%;
13
+ height: 100%;
14
+ margin: 0;
15
+ overflow: hidden;
16
+ background: transparent;
17
+ }
18
+
19
+ body {
20
+ color: #fff;
21
+ font-family: Inter, system-ui, sans-serif;
22
+ }
23
+
24
+ .scoreboard {
25
+ position: absolute;
26
+ top: 5%;
27
+ left: 50%;
28
+ transform: translateX(-50%);
29
+ display: grid;
30
+ grid-template-columns: 16rem 5rem 5rem 16rem;
31
+ align-items: stretch;
32
+ background: rgba(8, 17, 27, .94);
33
+ border-radius: .8rem;
34
+ overflow: hidden;
35
+ box-shadow: 0 1rem 3rem rgba(0, 0, 0, .35);
36
+ border: 1px solid rgba(255, 255, 255, .18);
37
+ }
38
+
39
+ .team {
40
+ display: flex;
41
+ align-items: center;
42
+ gap: .8rem;
43
+ padding: 1rem 1.2rem;
44
+ font-weight: 800;
45
+ letter-spacing: .04em;
46
+ }
47
+
48
+ .team.away {
49
+ justify-content: flex-end;
50
+ text-align: right;
51
+ }
52
+
53
+ .badge {
54
+ width: 2rem;
55
+ height: 2rem;
56
+ display: grid;
57
+ place-items: center;
58
+ border-radius: 50%;
59
+ background: #19b76b;
60
+ font-size: .72rem;
61
+ }
62
+
63
+ .away .badge {
64
+ background: #ea4b35;
65
+ order: 2;
66
+ }
67
+
68
+ .score {
69
+ display: grid;
70
+ place-items: center;
71
+ background: #fff;
72
+ color: #0b1722;
73
+ font-size: 2rem;
74
+ font-weight: 900;
75
+ }
76
+
77
+ .clock {
78
+ grid-column: 1 / -1;
79
+ background: #19b76b;
80
+ padding: .3rem;
81
+ text-align: center;
82
+ font-size: .85rem;
83
+ font-weight: 800;
84
+ letter-spacing: .14em;
85
+ }
86
+ </style>
87
+ </head>
88
+ <body>
89
+ <section class="scoreboard">
90
+ <div class="team"><span class="badge">H</span><span id="home">HOME</span></div>
91
+ <div class="score" id="homeScore">0</div>
92
+ <div class="score" id="awayScore">0</div>
93
+ <div class="team away"><span class="badge">A</span><span id="away">AWAY</span></div>
94
+ <div class="clock" id="clock">00:00</div>
95
+ </section>
96
+ <script>
97
+
98
+ const $ = (name, value) => {
99
+ const element = document.getElementById(name);
100
+ if (element) {
101
+ if (value !== undefined) element.textContent = String(value);
102
+ else return element;
103
+ }
104
+ }
105
+ window.addEventListener("nebular-overlay:update", ({detail}) => {
106
+ if (detail.home?.name != null) $("home", detail.home.name);
107
+ if (detail.home?.score != null) $("homeScore", detail.home.score);
108
+ if (detail.away?.name != null) $("away", detail.away.name);
109
+ if (detail.away?.score != null) $("awayScore", detail.away.score);
110
+ if (detail.clock != null) $("clock", detail.clock);
111
+ window.invalidate?.()
112
+ });
113
+ </script>
114
+ </body>
115
+ </html>
@@ -0,0 +1,54 @@
1
+ {
2
+ "instructions": "Enter both team names, update their scores and set the match clock. Press Update whenever the score or clock changes; omitted fields retain their current values.",
3
+ "meta": {
4
+ "home/name": {
5
+ "type": "string",
6
+ "phase": "edit",
7
+ "label": "Home team", "hint": "Enter team name",
8
+ "default": "HOME"
9
+ },
10
+ "home/playName": {
11
+ "type": "string",
12
+ "phase": "play",
13
+ "label": "Home team", "hint": "Home-team name displayed during play",
14
+ "source": "home/name",
15
+ "readonly": true
16
+ },
17
+ "home/score": {
18
+ "type": "number",
19
+ "phase": "play",
20
+ "label": "Home score", "hint": "Enter score",
21
+ "min": 0,
22
+ "default": 0,
23
+ "break": true
24
+ },
25
+ "away/name": {
26
+ "type": "string",
27
+ "phase": "edit",
28
+ "label": "Away team", "hint": "Enter team name",
29
+ "default": "AWAY"
30
+ },
31
+ "away/playName": {
32
+ "type": "string",
33
+ "phase": "play",
34
+ "label": "Away team", "hint": "Away-team name displayed during play",
35
+ "source": "away/name",
36
+ "readonly": true
37
+ },
38
+ "away/score": {
39
+ "type": "number",
40
+ "phase": "play",
41
+ "label": "Away score", "hint": "Enter score",
42
+ "min": 0,
43
+ "default": 0,
44
+ "break": true
45
+ },
46
+ "clock": {
47
+ "type": "string",
48
+ "phase": "play",
49
+ "label": "Match clock", "hint": "e.g. 45:00",
50
+ "pattern": "^[0-9]{1,3}:[0-5][0-9]$",
51
+ "default": "00:00"
52
+ }
53
+ }
54
+ }