@homie-rocks/studio 0.19.2 → 0.21.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.
@@ -0,0 +1,174 @@
1
+ /* The Game Lab: a dark, crisp tool for one mechanic at a time. Everything is drawn by the browser: no web fonts, no
2
+ * images. Labels are small capitals in the system's monospace; the accent is amber, Today is a cool blue. */
3
+ :root {
4
+ --bg: #080b12;
5
+ --panel: #0e1320;
6
+ --panel2: #131a2a;
7
+ --raise: #1a2236;
8
+ --line: #232c42;
9
+ --line2: #2e3954;
10
+ --text: #e7eaf3;
11
+ --dim: #8d96b0;
12
+ --faint: #59627c;
13
+ --accent: #ffad3b;
14
+ --accent-ink: #1b1204;
15
+ --new: #ffad3b;
16
+ --today: #7cc4ff;
17
+ --bad: #ff5d6c;
18
+ --ok: #4fe0a0;
19
+ --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
20
+ --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
21
+ color-scheme: dark;
22
+ }
23
+ * { box-sizing: border-box; }
24
+ html, body { margin: 0; background: var(--bg); color: var(--text); font: 13px/1.35 var(--sans); }
25
+ body { min-height: 100vh; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto 1fr; overflow-x: hidden; }
26
+ button, select { font: inherit; color: inherit; }
27
+ [hidden] { display: none !important; }
28
+ .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
29
+
30
+ /* ------------------------------------------------------------------ bars and buttons */
31
+ .bar { display: flex; align-items: center; gap: 10px; padding: 8px 14px; background: var(--panel); border-bottom: 1px solid var(--line); }
32
+ .bar.top { padding-top: max(8px, env(safe-area-inset-top)); gap: 14px; }
33
+ .brand { display: flex; align-items: center; gap: 9px; font: 800 13px/1 var(--mono); letter-spacing: .32em; }
34
+ .brand .mark { width: 12px; height: 12px; background: var(--accent); transform: rotate(45deg); box-shadow: 0 0 0 3px rgba(255, 173, 59, .16); }
35
+ .title { display: flex; align-items: baseline; gap: 8px; min-width: 0; flex: 1 1 auto; font: 600 13px/1.2 var(--mono); color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
36
+ .title b { color: var(--text); font-weight: 700; }
37
+ .title .sep { color: var(--faint); }
38
+ .status { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
39
+ .chip { display: inline-flex; align-items: center; gap: 6px; height: 22px; padding: 0 8px; border: 1px solid var(--line2); background: var(--panel2); font: 700 10.5px/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--dim); white-space: nowrap; }
40
+ .chip .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
41
+ .chip.ok { color: var(--ok); border-color: rgba(79, 224, 160, .35); }
42
+ .chip.bad { color: var(--bad); border-color: rgba(255, 93, 108, .4); cursor: help; }
43
+ .chip.warn { color: var(--accent); border-color: rgba(255, 173, 59, .4); }
44
+ .chip.busy .dot { animation: blink 1s steps(2, start) infinite; }
45
+ @keyframes blink { to { visibility: hidden; } }
46
+
47
+ .tools { gap: 12px; flex-wrap: wrap; row-gap: 8px; }
48
+ .group { display: flex; align-items: center; gap: 2px; }
49
+ .group.grow { flex: 1; }
50
+ .group:empty { display: none; }
51
+ .group .label { font: 700 10px/1 var(--mono); letter-spacing: .14em; color: var(--faint); margin-right: 6px; text-transform: uppercase; }
52
+ .bar button, .deck button, .tune button, .recbar button {
53
+ height: 26px; min-width: 26px; padding: 0 9px; border: 1px solid var(--line2); background: var(--panel2); color: var(--text);
54
+ font: 700 11px/1 var(--mono); letter-spacing: .06em; text-transform: uppercase; cursor: pointer; border-radius: 2px;
55
+ }
56
+ .bar button:hover, .deck button:hover, .tune button:hover { border-color: var(--faint); background: var(--raise); }
57
+ button.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
58
+ button.on:hover { background: #ffbd61; border-color: #ffbd61; }
59
+ button:disabled { opacity: .4; cursor: default; }
60
+ button:focus-visible, select:focus-visible, input:focus-visible { outline: 2px solid var(--today); outline-offset: 1px; }
61
+ button.wide { min-width: 64px; }
62
+ button.rec { color: #ff8a95; }
63
+ button.rec.on { background: var(--bad); border-color: var(--bad); color: #fff; }
64
+ .select select { height: 26px; padding: 0 26px 0 9px; border: 1px solid var(--line2); background: var(--panel2) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%238d96b0'/%3E%3C/svg%3E") no-repeat right 9px center; appearance: none; font: 700 11px/1 var(--mono); letter-spacing: .04em; border-radius: 2px; max-width: 220px; }
65
+
66
+ /* ------------------------------------------------------------------ the work area */
67
+ .work { display: grid; grid-template-columns: minmax(0, 1fr) 300px; grid-template-rows: minmax(260px, 1fr) auto; grid-template-areas: "stage tune" "deck tune"; min-height: 0; }
68
+ /* A computer: the whole lab in the window (the tunables scroll in their own column). */
69
+ @media (min-width: 1101px) { body { height: 100vh; min-height: 0; } .tune { min-height: 0; overflow: hidden; } }
70
+ .stage { grid-area: stage; position: relative; overflow: hidden; min-height: 260px;
71
+ background: radial-gradient(rgba(141, 150, 176, .14) 1px, transparent 1.2px) 0 0 / 18px 18px, #0a0e18; }
72
+ .slot { position: absolute; }
73
+ .slot .frame { position: absolute; left: 0; right: 0; top: 26px; bottom: 34px; overflow: hidden; background: #000; box-shadow: 0 0 0 1px var(--line2), 0 12px 40px rgba(0, 0, 0, .45); }
74
+ .slot iframe { position: absolute; left: 0; top: 0; border: 0; transform-origin: 0 0; background: #000; }
75
+ .slot[data-pane="new"] .frame { box-shadow: 0 0 0 1px rgba(255, 173, 59, .55), 0 12px 40px rgba(0, 0, 0, .45); }
76
+ .slot[data-pane="today"] .frame { box-shadow: 0 0 0 1px rgba(124, 196, 255, .45), 0 12px 40px rgba(0, 0, 0, .45); }
77
+ .slot.ghost { pointer-events: none; }
78
+ .slot.ghost .frame { background: transparent; box-shadow: none; opacity: .5; }
79
+ .slot.ghost .tag { left: auto; right: 0; flex-direction: row-reverse; }
80
+ .slot.ghost .caption { left: auto; right: 0; flex-direction: row-reverse; }
81
+ .tag { position: absolute; left: 0; top: 0; height: 20px; display: flex; align-items: center; gap: 6px; pointer-events: none; max-width: 100%; }
82
+ .tag span { padding: 4px 7px 3px; font: 800 10.5px/1 var(--mono); letter-spacing: .14em; border: 1px solid; background: rgba(8, 11, 18, .86); }
83
+ .tag.new span { color: var(--new); border-color: rgba(255, 173, 59, .7); }
84
+ .tag.today span { color: var(--today); border-color: rgba(124, 196, 255, .6); }
85
+ .tag small { font: 600 10.5px/1.2 var(--mono); color: var(--dim); background: rgba(8, 11, 18, .7); padding: 3px 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
86
+ .caption { position: absolute; left: 0; bottom: 0; height: 26px; display: flex; gap: 6px; align-items: stretch; pointer-events: none; max-width: 100%; }
87
+ .caption:empty { display: none; }
88
+ .caption b { padding: 5px 8px 4px; font: 800 12.5px/1 var(--mono); letter-spacing: .2em; border: 2px solid; background: rgba(8, 11, 18, .88); }
89
+ .caption span { padding: 6px 9px; font: 700 11.5px/1 var(--mono); color: var(--text); border: 1px solid var(--line2); background: rgba(8, 11, 18, .82); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
90
+ .veil { position: absolute; left: 0; right: 0; top: 26px; bottom: 34px; display: grid; place-items: center; padding: 18px; text-align: center; background: rgba(8, 11, 18, .82); font: 600 12.5px/1.5 var(--mono); color: var(--dim); }
91
+ .veil b { display: block; color: var(--text); margin-bottom: 6px; letter-spacing: .1em; }
92
+ .recbar { position: absolute; left: 50%; top: 10px; transform: translateX(-50%); display: flex; align-items: center; gap: 10px; padding: 6px 8px 6px 12px; background: rgba(40, 8, 14, .92); border: 1px solid var(--bad); font: 700 11px/1 var(--mono); letter-spacing: .06em; text-transform: uppercase; z-index: 3; }
93
+ .recbar .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--bad); animation: blink 1s steps(2, start) infinite; }
94
+
95
+ /* ------------------------------------------------------------------ tunables */
96
+ .tune { grid-area: tune; display: flex; flex-direction: column; min-height: 0; background: var(--panel); border-left: 1px solid var(--line); }
97
+ .tune-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; padding: 12px 14px 8px; font: 800 11px/1 var(--mono); letter-spacing: .2em; }
98
+ .tune-head small { font: 600 10.5px/1 var(--mono); letter-spacing: 0; color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
99
+ .tune-list { flex: 1; overflow: auto; padding: 0 14px 10px; }
100
+ .tune-group { margin: 12px 0 4px; font: 700 10px/1 var(--mono); letter-spacing: .18em; color: var(--faint); text-transform: uppercase; }
101
+ .knob { padding: 9px 0 10px; border-bottom: 1px solid var(--line); }
102
+ .knob .row { display: flex; align-items: baseline; gap: 8px; }
103
+ .knob .name { font: 700 12px/1.2 var(--mono); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
104
+ .knob.changed .name::before { content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 6px; background: var(--accent); transform: rotate(45deg) translateY(-1px); }
105
+ .knob .val { margin-left: auto; font: 800 12px/1 var(--mono); color: var(--new); font-variant-numeric: tabular-nums; }
106
+ .knob .unit { font: 600 10.5px/1 var(--mono); color: var(--faint); }
107
+ .knob .was { display: block; margin-top: 3px; font: 600 10.5px/1.3 var(--mono); color: var(--today); }
108
+ .knob .note { display: block; margin-top: 3px; font: 12px/1.35 var(--sans); color: var(--dim); }
109
+ .knob .track { position: relative; margin-top: 8px; height: 18px; }
110
+ .knob input[type=range] { position: absolute; inset: 0; width: 100%; margin: 0; appearance: none; background: transparent; cursor: pointer; }
111
+ .knob input[type=range]::-webkit-slider-runnable-track { height: 4px; background: linear-gradient(90deg, var(--accent) var(--fill, 50%), var(--line2) var(--fill, 50%)); border-radius: 2px; }
112
+ .knob input[type=range]::-moz-range-track { height: 4px; background: var(--line2); border-radius: 2px; }
113
+ .knob input[type=range]::-moz-range-progress { height: 4px; background: var(--accent); }
114
+ .knob input[type=range]::-webkit-slider-thumb { appearance: none; width: 14px; height: 14px; margin-top: -5px; background: var(--text); border: 2px solid var(--accent); transform: rotate(45deg); }
115
+ .knob input[type=range]::-moz-range-thumb { width: 12px; height: 12px; background: var(--text); border: 2px solid var(--accent); border-radius: 0; }
116
+ .knob .tick { position: absolute; top: 1px; width: 2px; height: 16px; background: var(--today); pointer-events: none; box-shadow: 0 0 0 1px rgba(8, 11, 18, .8); }
117
+ .tune-foot { display: flex; gap: 6px; padding: 10px 14px max(12px, env(safe-area-inset-bottom)); border-top: 1px solid var(--line); }
118
+ .tune-foot .primary { flex: 1; }
119
+ .tune-foot .primary:not(:disabled) { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
120
+ .tune-empty { margin: 8px 0; font: 12.5px/1.5 var(--sans); color: var(--dim); }
121
+ .tune-empty code { font: 600 11.5px/1 var(--mono); color: var(--text); }
122
+
123
+ /* ------------------------------------------------------------------ timeline and graph */
124
+ .deck { grid-area: deck; padding: 10px 14px 12px; background: var(--panel); border-top: 1px solid var(--line); min-width: 0; }
125
+ .transport { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; row-gap: 8px; }
126
+ .counter { margin-left: auto; font: 800 13px/1 var(--mono); letter-spacing: .12em; color: var(--accent); font-variant-numeric: tabular-nums; white-space: nowrap; }
127
+ .legend { display: flex; gap: 14px; margin: 10px 0 6px; font: 700 10px/1 var(--mono); letter-spacing: .16em; color: var(--dim); text-transform: uppercase; flex-wrap: wrap; }
128
+ .legend i { display: inline-block; width: 9px; height: 9px; margin-right: 6px; vertical-align: -1px; }
129
+ .legend .right { margin-left: auto; letter-spacing: .08em; }
130
+ .lines { position: relative; }
131
+ .lines canvas { display: block; width: 100%; cursor: ew-resize; touch-action: none; }
132
+ #timeline { height: 58px; }
133
+ #graph { height: 132px; margin-top: 4px; }
134
+ .tracks { display: flex; gap: 2px; margin-top: 10px; flex-wrap: wrap; }
135
+ .tracks button { height: 22px; font-size: 10.5px; }
136
+ .hint { margin: 8px 0 0; font: 12px/1.4 var(--sans); color: var(--dim); min-height: 1em; }
137
+ .hint code { font: 600 11px/1 var(--mono); color: var(--text); }
138
+
139
+ /* ------------------------------------------------------------------ a phone, or a narrow window */
140
+ @media (max-width: 1100px) {
141
+ .work { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto auto; grid-template-areas: "stage" "deck" "tune"; }
142
+ .stage { height: min(62vh, 620px); }
143
+ .tune { border-left: 0; border-top: 1px solid var(--line); }
144
+ .tune-list { max-height: none; }
145
+ }
146
+ @media (max-width: 640px) {
147
+ .bar { padding: 7px 10px; }
148
+ .bar.top { flex-wrap: wrap; row-gap: 6px; }
149
+ .title { flex-basis: 100%; }
150
+ .title #take-name { overflow: hidden; text-overflow: ellipsis; }
151
+ .status { margin-left: 0; width: 100%; justify-content: flex-start; }
152
+ .legend .right { display: none; }
153
+ .tools { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
154
+ .tools::-webkit-scrollbar { display: none; }
155
+ .group.grow { display: none; }
156
+ .stage { height: 58vh; min-height: 300px; }
157
+ .deck { padding: 10px 10px 12px; }
158
+ .transport { gap: 8px; }
159
+ .counter { width: 100%; margin-left: 0; order: -1; font-size: 14px; }
160
+ .bar button, .deck button, .tune button { height: 32px; min-width: 32px; padding: 0 9px; }
161
+ .caption b { font-size: 12px; padding: 5px 7px 4px; }
162
+ .caption span { font-size: 11px; padding: 5px 7px; }
163
+ #graph { height: 116px; }
164
+ }
165
+
166
+ /* ------------------------------------------------------------------ the index of games */
167
+ body.index { display: block; }
168
+ body.index main { max-width: 640px; margin: 10vh auto; padding: 0 20px; }
169
+ body.index .brand { margin: 0 0 18px; }
170
+ body.index h1 { font: 800 28px/1.1 var(--sans); margin: 0 0 18px; }
171
+ body.index .games { list-style: none; padding: 0; margin: 0; border-top: 1px solid var(--line); }
172
+ body.index .games li { padding: 14px 0; border-bottom: 1px solid var(--line); }
173
+ body.index .games a { color: var(--accent); font: 700 15px/1 var(--mono); text-decoration: none; letter-spacing: .04em; }
174
+ body.index .games small { margin-left: 10px; color: var(--faint); font: 600 11px/1 var(--mono); }