vargai 0.3.2 → 0.4.0-alpha10

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 (64) hide show
  1. package/biome.json +6 -1
  2. package/docs/index.html +1130 -0
  3. package/docs/prompting.md +326 -0
  4. package/docs/react.md +834 -0
  5. package/package.json +14 -5
  6. package/src/cli/commands/index.ts +2 -4
  7. package/src/cli/commands/render.ts +136 -0
  8. package/src/cli/commands/studio.ts +47 -0
  9. package/src/cli/index.ts +6 -1
  10. package/src/react/elements.ts +146 -0
  11. package/src/react/examples/branching.tsx +66 -0
  12. package/src/react/examples/captions-demo.tsx +37 -0
  13. package/src/react/examples/character-video.tsx +84 -0
  14. package/src/react/examples/grid.tsx +53 -0
  15. package/src/react/examples/layouts-demo.tsx +57 -0
  16. package/src/react/examples/madi.tsx +60 -0
  17. package/src/react/examples/music-test.tsx +35 -0
  18. package/src/react/examples/onlyfans-1m/workflow.tsx +88 -0
  19. package/src/react/examples/orange-portrait.tsx +41 -0
  20. package/src/react/examples/split-element-demo.tsx +60 -0
  21. package/src/react/examples/split-layout-demo.tsx +60 -0
  22. package/src/react/examples/split.tsx +41 -0
  23. package/src/react/examples/video-grid.tsx +46 -0
  24. package/src/react/index.ts +43 -0
  25. package/src/react/layouts/grid.tsx +28 -0
  26. package/src/react/layouts/index.ts +2 -0
  27. package/src/react/layouts/split.tsx +20 -0
  28. package/src/react/react.test.ts +309 -0
  29. package/src/react/render.ts +21 -0
  30. package/src/react/renderers/animate.ts +59 -0
  31. package/src/react/renderers/captions.ts +297 -0
  32. package/src/react/renderers/clip.ts +258 -0
  33. package/src/react/renderers/context.ts +17 -0
  34. package/src/react/renderers/image.ts +109 -0
  35. package/src/react/renderers/index.ts +22 -0
  36. package/src/react/renderers/music.ts +60 -0
  37. package/src/react/renderers/packshot.ts +84 -0
  38. package/src/react/renderers/progress.ts +173 -0
  39. package/src/react/renderers/render.ts +319 -0
  40. package/src/react/renderers/slider.ts +69 -0
  41. package/src/react/renderers/speech.ts +53 -0
  42. package/src/react/renderers/split.ts +91 -0
  43. package/src/react/renderers/subtitle.ts +16 -0
  44. package/src/react/renderers/swipe.ts +75 -0
  45. package/src/react/renderers/title.ts +17 -0
  46. package/src/react/renderers/utils.ts +124 -0
  47. package/src/react/renderers/video.ts +127 -0
  48. package/src/react/runtime/jsx-dev-runtime.ts +43 -0
  49. package/src/react/runtime/jsx-runtime.ts +35 -0
  50. package/src/react/types.ts +239 -0
  51. package/src/studio/index.ts +26 -0
  52. package/src/studio/scanner.ts +102 -0
  53. package/src/studio/server.ts +554 -0
  54. package/src/studio/stages.ts +251 -0
  55. package/src/studio/step-renderer.ts +279 -0
  56. package/src/studio/types.ts +60 -0
  57. package/src/studio/ui/cache.html +303 -0
  58. package/src/studio/ui/index.html +1820 -0
  59. package/tsconfig.cli.json +8 -0
  60. package/tsconfig.json +6 -2
  61. package/bun.lock +0 -1255
  62. package/docs/plan.md +0 -66
  63. package/docs/todo.md +0 -14
  64. /package/docs/{varg-sdk.md → sdk.md} +0 -0
@@ -0,0 +1,303 @@
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>cache viewer - varg studio</title>
7
+ <style>
8
+ * { box-sizing: border-box; margin: 0; padding: 0; }
9
+ body {
10
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
11
+ background: #0a0a0a;
12
+ color: #fafafa;
13
+ min-height: 100vh;
14
+ }
15
+ header {
16
+ height: 48px;
17
+ padding: 0 1rem;
18
+ border-bottom: 1px solid #222;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: space-between;
22
+ gap: 1rem;
23
+ }
24
+ .logo { font-weight: 600; font-size: 0.875rem; }
25
+ .nav { display: flex; gap: 0.25rem; }
26
+ .nav-btn {
27
+ padding: 0.5rem 0.75rem;
28
+ border-radius: 0.375rem;
29
+ border: none;
30
+ background: transparent;
31
+ color: #888;
32
+ font-size: 0.8rem;
33
+ cursor: pointer;
34
+ text-decoration: none;
35
+ transition: all 0.15s;
36
+ }
37
+ .nav-btn:hover { color: #fff; background: #141414; }
38
+ .nav-btn.active { color: #fff; background: #141414; }
39
+ .header-right { display: flex; align-items: center; gap: 1rem; }
40
+ .stats { color: #666; font-size: 0.8rem; }
41
+ .refresh-btn {
42
+ padding: 0.375rem 0.75rem;
43
+ border-radius: 0.375rem;
44
+ border: 1px solid #333;
45
+ background: transparent;
46
+ color: #888;
47
+ cursor: pointer;
48
+ font-size: 0.8rem;
49
+ }
50
+ .refresh-btn:hover { border-color: #555; color: #fff; }
51
+ .filters {
52
+ padding: 1rem 2rem;
53
+ display: flex;
54
+ gap: 0.5rem;
55
+ }
56
+ .filter-btn {
57
+ padding: 0.5rem 1rem;
58
+ border-radius: 0.5rem;
59
+ border: 1px solid #333;
60
+ background: transparent;
61
+ color: #888;
62
+ cursor: pointer;
63
+ font-size: 0.8rem;
64
+ transition: all 0.2s;
65
+ }
66
+ .filter-btn:hover { border-color: #555; color: #fff; }
67
+ .filter-btn.active { background: #fff; color: #000; border-color: #fff; }
68
+ .grid {
69
+ display: grid;
70
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
71
+ gap: 1rem;
72
+ padding: 1rem 2rem 2rem;
73
+ }
74
+ .card {
75
+ background: #141414;
76
+ border-radius: 0.75rem;
77
+ overflow: hidden;
78
+ border: 1px solid #222;
79
+ transition: border-color 0.2s;
80
+ }
81
+ .card:hover { border-color: #444; }
82
+ .card-media {
83
+ aspect-ratio: 16/9;
84
+ background: #000;
85
+ display: flex;
86
+ align-items: center;
87
+ justify-content: center;
88
+ overflow: hidden;
89
+ cursor: pointer;
90
+ }
91
+ .card-media img, .card-media video {
92
+ width: 100%;
93
+ height: 100%;
94
+ object-fit: contain;
95
+ }
96
+ .card-info { padding: 0.875rem; }
97
+ .card-type {
98
+ display: inline-block;
99
+ padding: 0.25rem 0.5rem;
100
+ border-radius: 0.25rem;
101
+ font-size: 0.7rem;
102
+ font-weight: 500;
103
+ text-transform: uppercase;
104
+ margin-bottom: 0.5rem;
105
+ }
106
+ .card-type.image { background: #1a3a1a; color: #4ade80; }
107
+ .card-type.video { background: #1a1a3a; color: #818cf8; }
108
+ .card-title {
109
+ font-size: 0.75rem;
110
+ color: #999;
111
+ word-break: break-all;
112
+ line-height: 1.4;
113
+ }
114
+ .card-meta {
115
+ display: flex;
116
+ gap: 1rem;
117
+ margin-top: 0.5rem;
118
+ font-size: 0.7rem;
119
+ color: #555;
120
+ }
121
+ .empty {
122
+ text-align: center;
123
+ padding: 4rem;
124
+ color: #666;
125
+ }
126
+ .modal {
127
+ display: none;
128
+ position: fixed;
129
+ inset: 0;
130
+ background: rgba(0,0,0,0.9);
131
+ z-index: 1000;
132
+ align-items: center;
133
+ justify-content: center;
134
+ padding: 2rem;
135
+ }
136
+ .modal.open { display: flex; }
137
+ .modal-content {
138
+ max-width: 90vw;
139
+ max-height: 90vh;
140
+ position: relative;
141
+ }
142
+ .modal-content img, .modal-content video {
143
+ max-width: 90vw;
144
+ max-height: 90vh;
145
+ object-fit: contain;
146
+ border-radius: 0.5rem;
147
+ }
148
+ .modal-close {
149
+ position: absolute;
150
+ top: -2.5rem;
151
+ right: 0;
152
+ background: none;
153
+ border: none;
154
+ color: #888;
155
+ font-size: 1.5rem;
156
+ cursor: pointer;
157
+ }
158
+ .modal-close:hover { color: #fff; }
159
+ .mute-toggle {
160
+ position: absolute;
161
+ bottom: 1rem;
162
+ right: 1rem;
163
+ padding: 0.5rem 0.75rem;
164
+ border-radius: 0.375rem;
165
+ border: 1px solid #444;
166
+ background: rgba(0,0,0,0.7);
167
+ color: #fff;
168
+ font-size: 0.75rem;
169
+ cursor: pointer;
170
+ }
171
+ .mute-toggle:hover { background: rgba(0,0,0,0.9); }
172
+ </style>
173
+ </head>
174
+ <body>
175
+ <header>
176
+ <div class="logo">varg studio</div>
177
+ <nav class="nav">
178
+ <a href="/editor" class="nav-btn">editor</a>
179
+ <a href="/cache" class="nav-btn active">cache</a>
180
+ </nav>
181
+ <div class="header-right">
182
+ <span class="stats" id="stats"></span>
183
+ <button class="refresh-btn" onclick="refresh()">refresh</button>
184
+ </div>
185
+ </header>
186
+
187
+ <div class="filters">
188
+ <button class="filter-btn active" data-filter="all">all</button>
189
+ <button class="filter-btn" data-filter="image">images</button>
190
+ <button class="filter-btn" data-filter="video">videos</button>
191
+ </div>
192
+
193
+ <div id="grid" class="grid"></div>
194
+
195
+ <div id="modal" class="modal" onclick="closeModal(event)">
196
+ <div class="modal-content">
197
+ <button class="modal-close" onclick="closeModal()">&times;</button>
198
+ <div id="modal-media"></div>
199
+ </div>
200
+ </div>
201
+
202
+ <script>
203
+ let items = [];
204
+ let filter = 'all';
205
+
206
+ async function fetchItems() {
207
+ const res = await fetch('/api/items');
208
+ items = await res.json();
209
+ updateStats();
210
+ renderGrid();
211
+ }
212
+
213
+ function updateStats() {
214
+ const images = items.filter(i => i.type === 'image').length;
215
+ const videos = items.filter(i => i.type === 'video').length;
216
+ document.getElementById('stats').textContent =
217
+ `${items.length} items (${images} images, ${videos} videos)`;
218
+ }
219
+
220
+ function formatSize(bytes) {
221
+ if (bytes < 1024) return `${bytes} B`;
222
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
223
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
224
+ }
225
+
226
+ function formatDate(dateStr) {
227
+ const date = new Date(dateStr);
228
+ return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
229
+ }
230
+
231
+ function renderGrid() {
232
+ const grid = document.getElementById('grid');
233
+ const filtered = filter === 'all' ? items : items.filter(i => i.type === filter);
234
+
235
+ if (filtered.length === 0) {
236
+ grid.innerHTML = '<div class="empty">no items found</div>';
237
+ return;
238
+ }
239
+
240
+ grid.innerHTML = filtered.map(item => {
241
+ const mediaUrl = `/api/media/${encodeURIComponent(item.id)}`;
242
+ const mediaHtml = item.type === 'video'
243
+ ? `<video src="${mediaUrl}" muted loop preload="metadata" onmouseenter="this.play()" onmouseleave="this.pause();this.currentTime=0"></video>`
244
+ : `<img src="${mediaUrl}" alt="${item.id}" loading="lazy">`;
245
+
246
+ return '<div class="card">' +
247
+ '<div class="card-media" onclick="openModal(\'' + item.type + '\', \'' + mediaUrl + '\')">' + mediaHtml + '</div>' +
248
+ '<div class="card-info">' +
249
+ '<span class="card-type ' + item.type + '">' + item.type + '</span>' +
250
+ '<div class="card-title">' + item.id + '</div>' +
251
+ '<div class="card-meta">' +
252
+ '<span>' + formatSize(item.size) + '</span>' +
253
+ '<span>' + formatDate(item.createdAt) + '</span>' +
254
+ '</div>' +
255
+ '</div>' +
256
+ '</div>';
257
+ }).join('');
258
+ }
259
+
260
+ function _refresh() { fetchItems(); }
261
+
262
+ document.querySelectorAll('.filter-btn').forEach(btn => {
263
+ btn.addEventListener('click', () => {
264
+ document.querySelectorAll('.filter-btn').forEach(b => { b.classList.remove('active'); });
265
+ btn.classList.add('active');
266
+ filter = btn.dataset.filter;
267
+ renderGrid();
268
+ });
269
+ });
270
+
271
+ function _openModal(type, url) {
272
+ const modal = document.getElementById('modal');
273
+ const mediaContainer = document.getElementById('modal-media');
274
+ if (type === 'video') {
275
+ mediaContainer.innerHTML = '<video id="modal-video" src="' + url + '" controls autoplay loop muted></video>' +
276
+ '<button class="mute-toggle" onclick="toggleMute()"><span id="mute-icon">muted</span></button>';
277
+ } else {
278
+ mediaContainer.innerHTML = `<img src="${url}">`;
279
+ }
280
+ modal.classList.add('open');
281
+ }
282
+
283
+ function _toggleMute() {
284
+ const video = document.getElementById('modal-video');
285
+ if (!video) return;
286
+ video.muted = !video.muted;
287
+ document.getElementById('mute-icon').textContent = video.muted ? 'muted' : 'unmuted';
288
+ }
289
+
290
+ function closeModal(e) {
291
+ if (e && e.target !== e.currentTarget) return;
292
+ document.getElementById('modal').classList.remove('open');
293
+ document.getElementById('modal-media').innerHTML = '';
294
+ }
295
+
296
+ document.addEventListener('keydown', (e) => {
297
+ if (e.key === 'Escape') closeModal();
298
+ });
299
+
300
+ fetchItems();
301
+ </script>
302
+ </body>
303
+ </html>