pa_encoder 0.1.0 → 0.2.1
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.
- package/README.md +191 -0
- package/dist/browser/index.js +17 -0
- package/dist/cli.js +144 -0
- package/dist/index.js +402 -160
- package/dist/ui/encoder.html +469 -0
- package/dist/ui/encoder.js +368 -0
- package/dist/ui/preview.html +20 -0
- package/dist/ui/preview.js +322 -0
- package/package.json +5 -3
|
@@ -0,0 +1,469 @@
|
|
|
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>pa_encoder</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--panel-bg: rgba(16, 16, 18, 0.92);
|
|
10
|
+
--panel-border: rgba(255, 255, 255, 0.12);
|
|
11
|
+
--text: rgba(255, 255, 255, 0.92);
|
|
12
|
+
--muted: rgba(255, 255, 255, 0.62);
|
|
13
|
+
|
|
14
|
+
--surface: rgba(255, 255, 255, 0.06);
|
|
15
|
+
--surface-2: rgba(255, 255, 255, 0.1);
|
|
16
|
+
--border: rgba(255, 255, 255, 0.14);
|
|
17
|
+
|
|
18
|
+
--primary: #2f6df6;
|
|
19
|
+
--primary-hover: #3d7bff;
|
|
20
|
+
|
|
21
|
+
--danger: #e5484d;
|
|
22
|
+
--danger-hover: #ff5a60;
|
|
23
|
+
|
|
24
|
+
--shadow: 0 14px 42px rgba(0, 0, 0, 0.45);
|
|
25
|
+
--radius: 14px;
|
|
26
|
+
--ring: 0 0 0 3px rgba(47, 109, 246, 0.35);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
html,
|
|
30
|
+
body {
|
|
31
|
+
margin: 0;
|
|
32
|
+
padding: 0;
|
|
33
|
+
background: transparent;
|
|
34
|
+
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto,
|
|
35
|
+
Helvetica, Arial;
|
|
36
|
+
color: var(--text);
|
|
37
|
+
overflow: hidden; /* prevent any page-level horizontal scroll */
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Preview fills the viewport */
|
|
41
|
+
#previewWrap {
|
|
42
|
+
position: fixed;
|
|
43
|
+
inset: 0;
|
|
44
|
+
z-index: 0;
|
|
45
|
+
}
|
|
46
|
+
#preview {
|
|
47
|
+
position: absolute;
|
|
48
|
+
inset: 0;
|
|
49
|
+
width: 100%;
|
|
50
|
+
height: 100%;
|
|
51
|
+
border: 0;
|
|
52
|
+
pointer-events: none; /* default: UI captures mouse */
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* UI overlay root */
|
|
56
|
+
#root {
|
|
57
|
+
position: fixed;
|
|
58
|
+
inset: 0;
|
|
59
|
+
z-index: 1;
|
|
60
|
+
pointer-events: none;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Panel */
|
|
64
|
+
#panel {
|
|
65
|
+
position: fixed;
|
|
66
|
+
pointer-events: auto;
|
|
67
|
+
|
|
68
|
+
width: clamp(320px, 34vw, 520px);
|
|
69
|
+
max-height: min(78vh, 720px);
|
|
70
|
+
|
|
71
|
+
background: var(--panel-bg);
|
|
72
|
+
border: 1px solid var(--panel-border);
|
|
73
|
+
border-radius: var(--radius);
|
|
74
|
+
box-shadow: var(--shadow);
|
|
75
|
+
backdrop-filter: blur(10px);
|
|
76
|
+
|
|
77
|
+
display: flex;
|
|
78
|
+
flex-direction: column;
|
|
79
|
+
overflow: hidden; /* scrolling happens in middle area */
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Dock positions */
|
|
83
|
+
body.dock-br #panel {
|
|
84
|
+
right: 16px;
|
|
85
|
+
bottom: 16px;
|
|
86
|
+
}
|
|
87
|
+
body.dock-bl #panel {
|
|
88
|
+
left: 16px;
|
|
89
|
+
bottom: 16px;
|
|
90
|
+
}
|
|
91
|
+
body.dock-tr #panel {
|
|
92
|
+
right: 16px;
|
|
93
|
+
top: 16px;
|
|
94
|
+
}
|
|
95
|
+
body.dock-tl #panel {
|
|
96
|
+
left: 16px;
|
|
97
|
+
top: 16px;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* Header */
|
|
101
|
+
.topbar {
|
|
102
|
+
display: flex;
|
|
103
|
+
align-items: center;
|
|
104
|
+
justify-content: space-between;
|
|
105
|
+
gap: 10px;
|
|
106
|
+
padding: 12px 12px 10px 12px;
|
|
107
|
+
border-bottom: 1px solid var(--border);
|
|
108
|
+
}
|
|
109
|
+
.title {
|
|
110
|
+
font-weight: 700;
|
|
111
|
+
font-size: 14px;
|
|
112
|
+
letter-spacing: 0.2px;
|
|
113
|
+
}
|
|
114
|
+
.topbtns {
|
|
115
|
+
display: flex;
|
|
116
|
+
gap: 8px;
|
|
117
|
+
align-items: center;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Controls area: scroll container */
|
|
121
|
+
.content {
|
|
122
|
+
flex: 1;
|
|
123
|
+
overflow-y: auto;
|
|
124
|
+
overflow-x: hidden; /* key: prevent horizontal scroll */
|
|
125
|
+
padding: 12px;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* Footer log: fixed height */
|
|
129
|
+
.log {
|
|
130
|
+
border-top: 1px solid var(--border);
|
|
131
|
+
padding: 10px 12px;
|
|
132
|
+
height: 128px;
|
|
133
|
+
overflow: auto;
|
|
134
|
+
|
|
135
|
+
background: rgba(0, 0, 0, 0.28);
|
|
136
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
137
|
+
"Liberation Mono", "Courier New", monospace;
|
|
138
|
+
font-size: 12.5px;
|
|
139
|
+
white-space: pre-wrap;
|
|
140
|
+
word-break: break-word;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Inputs */
|
|
144
|
+
button,
|
|
145
|
+
input,
|
|
146
|
+
select {
|
|
147
|
+
border-radius: 10px;
|
|
148
|
+
border: 1px solid var(--border);
|
|
149
|
+
background: var(--surface);
|
|
150
|
+
color: var(--text);
|
|
151
|
+
padding: 10px 12px;
|
|
152
|
+
font-size: 14px;
|
|
153
|
+
outline: none;
|
|
154
|
+
box-sizing: border-box;
|
|
155
|
+
|
|
156
|
+
min-width: 0; /* key: allow shrinking inside grid */
|
|
157
|
+
width: 100%; /* key: fit grid cell */
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
input:focus,
|
|
161
|
+
select:focus,
|
|
162
|
+
button:focus {
|
|
163
|
+
box-shadow: var(--ring);
|
|
164
|
+
border-color: rgba(47, 109, 246, 0.55);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
button {
|
|
168
|
+
cursor: pointer;
|
|
169
|
+
user-select: none;
|
|
170
|
+
background: var(--surface-2);
|
|
171
|
+
}
|
|
172
|
+
button:hover {
|
|
173
|
+
background: rgba(255, 255, 255, 0.12);
|
|
174
|
+
}
|
|
175
|
+
button:disabled {
|
|
176
|
+
opacity: 0.55;
|
|
177
|
+
cursor: not-allowed;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.btnSmall {
|
|
181
|
+
padding: 8px 10px;
|
|
182
|
+
font-size: 13px;
|
|
183
|
+
border-radius: 10px;
|
|
184
|
+
width: auto; /* small buttons shouldn't stretch */
|
|
185
|
+
min-width: 0;
|
|
186
|
+
}
|
|
187
|
+
.btnGhost {
|
|
188
|
+
background: transparent;
|
|
189
|
+
}
|
|
190
|
+
.btnGhost:hover {
|
|
191
|
+
background: rgba(255, 255, 255, 0.08);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.btnPrimary {
|
|
195
|
+
background: var(--primary);
|
|
196
|
+
border-color: rgba(47, 109, 246, 0.55);
|
|
197
|
+
}
|
|
198
|
+
.btnPrimary:hover {
|
|
199
|
+
background: var(--primary-hover);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.btnDanger {
|
|
203
|
+
background: var(--danger);
|
|
204
|
+
border-color: rgba(229, 72, 77, 0.65);
|
|
205
|
+
}
|
|
206
|
+
.btnDanger:hover {
|
|
207
|
+
background: var(--danger-hover);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/* Form rows */
|
|
211
|
+
.row {
|
|
212
|
+
display: grid;
|
|
213
|
+
grid-template-columns: 110px minmax(0, 1fr); /* key */
|
|
214
|
+
gap: 10px;
|
|
215
|
+
align-items: center;
|
|
216
|
+
margin: 10px 0;
|
|
217
|
+
}
|
|
218
|
+
.row2 {
|
|
219
|
+
display: grid;
|
|
220
|
+
grid-template-columns:
|
|
221
|
+
110px minmax(0, 1fr)
|
|
222
|
+
110px minmax(0, 1fr); /* key */
|
|
223
|
+
gap: 10px;
|
|
224
|
+
align-items: center;
|
|
225
|
+
margin: 10px 0;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
label {
|
|
229
|
+
color: var(--muted);
|
|
230
|
+
font-size: 13px;
|
|
231
|
+
min-width: 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.btnRow {
|
|
235
|
+
display: grid;
|
|
236
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
237
|
+
gap: 10px;
|
|
238
|
+
margin-top: 12px;
|
|
239
|
+
}
|
|
240
|
+
.btnRow > button {
|
|
241
|
+
width: 100%;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Details sections */
|
|
245
|
+
details {
|
|
246
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
247
|
+
border-radius: 12px;
|
|
248
|
+
padding: 10px 10px 6px 10px;
|
|
249
|
+
background: rgba(255, 255, 255, 0.03);
|
|
250
|
+
margin: 12px 0;
|
|
251
|
+
overflow: hidden; /* avoid inner horizontal overflow */
|
|
252
|
+
}
|
|
253
|
+
summary {
|
|
254
|
+
cursor: pointer;
|
|
255
|
+
list-style: none;
|
|
256
|
+
font-weight: 650;
|
|
257
|
+
font-size: 13px;
|
|
258
|
+
color: rgba(255, 255, 255, 0.82);
|
|
259
|
+
display: flex;
|
|
260
|
+
align-items: center;
|
|
261
|
+
justify-content: space-between;
|
|
262
|
+
gap: 10px;
|
|
263
|
+
user-select: none;
|
|
264
|
+
}
|
|
265
|
+
summary::-webkit-details-marker {
|
|
266
|
+
display: none;
|
|
267
|
+
}
|
|
268
|
+
.summaryHint {
|
|
269
|
+
color: var(--muted);
|
|
270
|
+
font-weight: 500;
|
|
271
|
+
font-size: 12px;
|
|
272
|
+
white-space: nowrap;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.hint {
|
|
276
|
+
color: var(--muted);
|
|
277
|
+
font-size: 12.5px;
|
|
278
|
+
line-height: 1.35;
|
|
279
|
+
margin-top: 10px;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* States */
|
|
283
|
+
body.hidden #panel {
|
|
284
|
+
display: none;
|
|
285
|
+
}
|
|
286
|
+
body.compact .content details,
|
|
287
|
+
body.compact .content .advancedRow,
|
|
288
|
+
body.compact .content .hint {
|
|
289
|
+
display: none;
|
|
290
|
+
}
|
|
291
|
+
body.passthrough #preview {
|
|
292
|
+
pointer-events: auto;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* Responsive */
|
|
296
|
+
@media (max-width: 520px) {
|
|
297
|
+
#panel {
|
|
298
|
+
width: calc(100vw - 32px);
|
|
299
|
+
}
|
|
300
|
+
.row,
|
|
301
|
+
.row2 {
|
|
302
|
+
grid-template-columns: minmax(0, 1fr);
|
|
303
|
+
}
|
|
304
|
+
.btnRow {
|
|
305
|
+
grid-template-columns: 1fr;
|
|
306
|
+
}
|
|
307
|
+
label {
|
|
308
|
+
margin-bottom: -6px;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
</style>
|
|
312
|
+
</head>
|
|
313
|
+
|
|
314
|
+
<body class="dock-br">
|
|
315
|
+
<div id="previewWrap">
|
|
316
|
+
<iframe id="preview"></iframe>
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
<div id="root">
|
|
320
|
+
<div id="panel" role="dialog" aria-label="pa_encoder UI">
|
|
321
|
+
<div class="topbar">
|
|
322
|
+
<div class="title">pa_encoder</div>
|
|
323
|
+
<div class="topbtns">
|
|
324
|
+
<button id="btnDock" class="btnSmall btnGhost" title="Change dock">
|
|
325
|
+
Dock
|
|
326
|
+
</button>
|
|
327
|
+
<button
|
|
328
|
+
id="btnCompact"
|
|
329
|
+
class="btnSmall btnGhost"
|
|
330
|
+
title="Toggle compact mode"
|
|
331
|
+
>
|
|
332
|
+
Compact
|
|
333
|
+
</button>
|
|
334
|
+
<button id="btnHide" class="btnSmall btnGhost" title="Hide UI">
|
|
335
|
+
Hide
|
|
336
|
+
</button>
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
|
|
340
|
+
<div class="content">
|
|
341
|
+
<div
|
|
342
|
+
class="advancedRow"
|
|
343
|
+
style="
|
|
344
|
+
display: flex;
|
|
345
|
+
gap: 10px;
|
|
346
|
+
flex-wrap: wrap;
|
|
347
|
+
margin-bottom: 10px;
|
|
348
|
+
"
|
|
349
|
+
>
|
|
350
|
+
<button
|
|
351
|
+
id="btnPassthrough"
|
|
352
|
+
class="btnSmall btnGhost"
|
|
353
|
+
title="Toggle passthrough (mouse to sketch)"
|
|
354
|
+
>
|
|
355
|
+
Passthrough: Off
|
|
356
|
+
</button>
|
|
357
|
+
<button
|
|
358
|
+
id="btnFocus"
|
|
359
|
+
class="btnSmall btnGhost"
|
|
360
|
+
title="Focus sketch for keyboard input"
|
|
361
|
+
>
|
|
362
|
+
Focus Sketch
|
|
363
|
+
</button>
|
|
364
|
+
</div>
|
|
365
|
+
|
|
366
|
+
<div class="row">
|
|
367
|
+
<label>Entry</label>
|
|
368
|
+
<input id="entry" />
|
|
369
|
+
</div>
|
|
370
|
+
|
|
371
|
+
<div class="row">
|
|
372
|
+
<label>Mode</label>
|
|
373
|
+
<select id="mode">
|
|
374
|
+
<option value="live">Live (realtime)</option>
|
|
375
|
+
<option value="frame">Frame (deterministic)</option>
|
|
376
|
+
</select>
|
|
377
|
+
</div>
|
|
378
|
+
|
|
379
|
+
<div class="row">
|
|
380
|
+
<label>Canvas</label>
|
|
381
|
+
<select id="canvas"></select>
|
|
382
|
+
</div>
|
|
383
|
+
|
|
384
|
+
<div class="row2">
|
|
385
|
+
<label>FPS</label>
|
|
386
|
+
<input id="fps" type="number" min="1" step="1" value="60" />
|
|
387
|
+
<label>Exporter</label>
|
|
388
|
+
<select id="exporter">
|
|
389
|
+
<option value="zip">ZIP (download)</option>
|
|
390
|
+
<option value="fs">FS (directory)</option>
|
|
391
|
+
<option value="best">Best (auto)</option>
|
|
392
|
+
</select>
|
|
393
|
+
</div>
|
|
394
|
+
|
|
395
|
+
<details open id="detailsLive">
|
|
396
|
+
<summary>
|
|
397
|
+
<span>Live settings</span>
|
|
398
|
+
<span class="summaryHint">duration / queue</span>
|
|
399
|
+
</summary>
|
|
400
|
+
|
|
401
|
+
<div class="row2">
|
|
402
|
+
<label>Policy</label>
|
|
403
|
+
<select id="policy">
|
|
404
|
+
<option value="drop">drop</option>
|
|
405
|
+
<option value="block">block</option>
|
|
406
|
+
</select>
|
|
407
|
+
<label>Conc.</label>
|
|
408
|
+
<input
|
|
409
|
+
id="concurrency"
|
|
410
|
+
type="number"
|
|
411
|
+
min="1"
|
|
412
|
+
step="1"
|
|
413
|
+
value="2"
|
|
414
|
+
/>
|
|
415
|
+
</div>
|
|
416
|
+
|
|
417
|
+
<div class="row2">
|
|
418
|
+
<label>MaxQueue</label>
|
|
419
|
+
<input id="maxQueue" type="number" min="0" step="1" value="8" />
|
|
420
|
+
<label>Duration</label>
|
|
421
|
+
<input id="duration" type="number" min="1" step="1" value="10" />
|
|
422
|
+
</div>
|
|
423
|
+
</details>
|
|
424
|
+
|
|
425
|
+
<details id="detailsFrame">
|
|
426
|
+
<summary>
|
|
427
|
+
<span>Frame settings</span>
|
|
428
|
+
<span class="summaryHint">frames / warmup</span>
|
|
429
|
+
</summary>
|
|
430
|
+
|
|
431
|
+
<div class="row2">
|
|
432
|
+
<label>Frames</label>
|
|
433
|
+
<input id="frames" type="number" min="1" step="1" value="300" />
|
|
434
|
+
<label>Warmup</label>
|
|
435
|
+
<input id="warmup" type="number" min="0" step="1" value="0" />
|
|
436
|
+
</div>
|
|
437
|
+
</details>
|
|
438
|
+
|
|
439
|
+
<div class="btnRow">
|
|
440
|
+
<button id="btnReload" class="btnGhost">Reload</button>
|
|
441
|
+
<button id="btnStart" class="btnPrimary">Start</button>
|
|
442
|
+
<button id="btnStop" class="btnDanger" disabled>Stop</button>
|
|
443
|
+
</div>
|
|
444
|
+
|
|
445
|
+
<div class="hint">
|
|
446
|
+
Hotkeys (only when not recording):
|
|
447
|
+
<br />
|
|
448
|
+
- H: hide UI
|
|
449
|
+
<br />
|
|
450
|
+
- P: toggle passthrough
|
|
451
|
+
<br />
|
|
452
|
+
- C: compact
|
|
453
|
+
<br />
|
|
454
|
+
- D: dock position
|
|
455
|
+
<br />
|
|
456
|
+
- Space: start
|
|
457
|
+
<br />
|
|
458
|
+
During recording, keyboard is not captured by the UI. Use Focus
|
|
459
|
+
Sketch if needed, then click the canvas to ensure focus.
|
|
460
|
+
</div>
|
|
461
|
+
</div>
|
|
462
|
+
|
|
463
|
+
<div id="log" class="log"></div>
|
|
464
|
+
</div>
|
|
465
|
+
</div>
|
|
466
|
+
|
|
467
|
+
<script type="module" src="/__pa_encoder__/ui/encoder.js"></script>
|
|
468
|
+
</body>
|
|
469
|
+
</html>
|