opencube 0.1.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.
- package/README.md +106 -0
- package/assets/opencode-icon-3d-three-preview.html +168 -0
- package/assets/opencode-icon.png +0 -0
- package/assets/opencode-pet-3d-spin-concept.svg +99 -0
- package/assets/opencode-pet-3d-spin-preview.html +324 -0
- package/assets/pixel-opencode-pet.svg +74 -0
- package/package.json +30 -0
- package/src/main.js +1282 -0
- package/src/pixel-pet-reference.cjs +134 -0
- package/src/plugin-server.cjs +169 -0
- package/src/plugin-shared.cjs +230 -0
- package/src/plugin-tui.cjs +7 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>opencode pet 3D spin preview</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #f4f4ef;
|
|
10
|
+
--ink: #050505;
|
|
11
|
+
--dark: #111;
|
|
12
|
+
--mid: #242424;
|
|
13
|
+
--plate: #d8d5cc;
|
|
14
|
+
--paper: #fff;
|
|
15
|
+
--accent: #ff5d73;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
* { box-sizing: border-box; }
|
|
19
|
+
html, body {
|
|
20
|
+
margin: 0;
|
|
21
|
+
width: 100%;
|
|
22
|
+
height: 100%;
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
background:
|
|
25
|
+
linear-gradient(180deg, rgba(255,255,255,.8), rgba(230,230,222,.85)),
|
|
26
|
+
radial-gradient(circle at 50% 42%, rgba(255,93,115,.12), transparent 34%),
|
|
27
|
+
var(--bg);
|
|
28
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
29
|
+
color: #151515;
|
|
30
|
+
user-select: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.toolbar {
|
|
34
|
+
position: fixed;
|
|
35
|
+
left: 24px;
|
|
36
|
+
top: 22px;
|
|
37
|
+
display: flex;
|
|
38
|
+
gap: 10px;
|
|
39
|
+
align-items: center;
|
|
40
|
+
z-index: 10;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
button {
|
|
44
|
+
appearance: none;
|
|
45
|
+
border: 2px solid #111;
|
|
46
|
+
background: white;
|
|
47
|
+
color: #111;
|
|
48
|
+
border-radius: 10px;
|
|
49
|
+
padding: 9px 13px;
|
|
50
|
+
font: inherit;
|
|
51
|
+
font-weight: 800;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
box-shadow: 0 4px 0 rgba(0,0,0,.18);
|
|
54
|
+
}
|
|
55
|
+
button:active { transform: translateY(2px); box-shadow: 0 2px 0 rgba(0,0,0,.18); }
|
|
56
|
+
.hint { font-size: 13px; opacity: .65; }
|
|
57
|
+
|
|
58
|
+
.pet-wrap {
|
|
59
|
+
position: absolute;
|
|
60
|
+
left: 50%;
|
|
61
|
+
top: 54%;
|
|
62
|
+
width: 300px;
|
|
63
|
+
height: 300px;
|
|
64
|
+
transform: translate(-50%, -50%);
|
|
65
|
+
cursor: grab;
|
|
66
|
+
touch-action: none;
|
|
67
|
+
perspective: 720px;
|
|
68
|
+
}
|
|
69
|
+
.pet-wrap.dragging { cursor: grabbing; }
|
|
70
|
+
|
|
71
|
+
.floor {
|
|
72
|
+
position: absolute;
|
|
73
|
+
left: 42px;
|
|
74
|
+
top: 226px;
|
|
75
|
+
width: 214px;
|
|
76
|
+
height: 58px;
|
|
77
|
+
border-radius: 999px;
|
|
78
|
+
background: rgba(0,0,0,.11);
|
|
79
|
+
transform: perspective(500px) rotateX(66deg);
|
|
80
|
+
}
|
|
81
|
+
.ring {
|
|
82
|
+
position: absolute;
|
|
83
|
+
left: 58px;
|
|
84
|
+
top: 231px;
|
|
85
|
+
width: 180px;
|
|
86
|
+
height: 46px;
|
|
87
|
+
border-radius: 999px;
|
|
88
|
+
border: 4px dashed rgba(255,93,115,.75);
|
|
89
|
+
transform: perspective(500px) rotateX(66deg);
|
|
90
|
+
opacity: 0;
|
|
91
|
+
transition: opacity 180ms steps(2, end);
|
|
92
|
+
}
|
|
93
|
+
.busy .ring { opacity: 1; }
|
|
94
|
+
|
|
95
|
+
.axis {
|
|
96
|
+
position: absolute;
|
|
97
|
+
left: 149px;
|
|
98
|
+
top: 42px;
|
|
99
|
+
width: 2px;
|
|
100
|
+
height: 230px;
|
|
101
|
+
background: repeating-linear-gradient(to bottom, rgba(0,0,0,.25) 0 7px, transparent 7px 14px);
|
|
102
|
+
opacity: 0;
|
|
103
|
+
transition: opacity 180ms steps(2, end);
|
|
104
|
+
}
|
|
105
|
+
.busy .axis { opacity: .55; }
|
|
106
|
+
|
|
107
|
+
.pet-3d {
|
|
108
|
+
position: absolute;
|
|
109
|
+
left: 50%;
|
|
110
|
+
top: 46px;
|
|
111
|
+
width: 190px;
|
|
112
|
+
height: 210px;
|
|
113
|
+
transform-style: preserve-3d;
|
|
114
|
+
transform-origin: 50% 58%;
|
|
115
|
+
transform: translateX(-50%) rotateY(0deg);
|
|
116
|
+
image-rendering: pixelated;
|
|
117
|
+
filter: drop-shadow(0 16px 12px rgba(0,0,0,.22));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.busy .pet-3d {
|
|
121
|
+
animation: spin3d 1.05s linear infinite;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@keyframes spin3d {
|
|
125
|
+
0% { transform: translateX(-50%) perspective(520px) rotateY(0deg); }
|
|
126
|
+
25% { transform: translateX(-50%) perspective(520px) rotateY(72deg); }
|
|
127
|
+
50% { transform: translateX(-50%) perspective(520px) rotateY(180deg); }
|
|
128
|
+
75% { transform: translateX(-50%) perspective(520px) rotateY(288deg); }
|
|
129
|
+
100% { transform: translateX(-50%) perspective(520px) rotateY(360deg); }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.solid {
|
|
133
|
+
position: absolute;
|
|
134
|
+
transform-style: preserve-3d;
|
|
135
|
+
}
|
|
136
|
+
.solid > i {
|
|
137
|
+
position: absolute;
|
|
138
|
+
display: block;
|
|
139
|
+
image-rendering: pixelated;
|
|
140
|
+
backface-visibility: visible;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.body3d {
|
|
144
|
+
left: 36px;
|
|
145
|
+
top: 32px;
|
|
146
|
+
width: 120px;
|
|
147
|
+
height: 144px;
|
|
148
|
+
--d: 56px;
|
|
149
|
+
}
|
|
150
|
+
.body3d .front { width: 120px; height: 144px; background: var(--ink); transform: translateZ(28px); }
|
|
151
|
+
.body3d .back { width: 120px; height: 144px; background: #070707; transform: rotateY(180deg) translateZ(28px); }
|
|
152
|
+
.body3d .left { left: -56px; width: 56px; height: 144px; background: #030303; transform-origin: right center; transform: rotateY(-90deg); }
|
|
153
|
+
.body3d .right { left: 120px; width: 56px; height: 144px; background: linear-gradient(90deg, #060606, #242424); transform-origin: left center; transform: rotateY(90deg); }
|
|
154
|
+
.body3d .top { top: -56px; width: 120px; height: 56px; background: #2c2c2c; transform-origin: bottom center; transform: rotateX(90deg); }
|
|
155
|
+
.body3d .bottom { top: 144px; width: 120px; height: 56px; background: #171717; transform-origin: top center; transform: rotateX(-90deg); }
|
|
156
|
+
.body3d .front::before {
|
|
157
|
+
content: "";
|
|
158
|
+
position: absolute;
|
|
159
|
+
left: 12px;
|
|
160
|
+
top: 12px;
|
|
161
|
+
width: 96px;
|
|
162
|
+
height: 18px;
|
|
163
|
+
background: #2d2d2d;
|
|
164
|
+
}
|
|
165
|
+
.body3d .front::after {
|
|
166
|
+
content: "";
|
|
167
|
+
position: absolute;
|
|
168
|
+
left: 10px;
|
|
169
|
+
bottom: 10px;
|
|
170
|
+
width: 100px;
|
|
171
|
+
height: 16px;
|
|
172
|
+
background: #171717;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.screen3d {
|
|
176
|
+
left: 58px;
|
|
177
|
+
top: 72px;
|
|
178
|
+
width: 76px;
|
|
179
|
+
height: 92px;
|
|
180
|
+
transform: translateZ(42px);
|
|
181
|
+
}
|
|
182
|
+
.screen3d .screen-front { width: 76px; height: 92px; background: #2d2d2d; transform: translateZ(7px); }
|
|
183
|
+
.screen3d .screen-left { left: -14px; width: 14px; height: 92px; background: #1a1a1a; transform-origin: right center; transform: rotateY(-90deg); }
|
|
184
|
+
.screen3d .screen-right { left: 76px; width: 14px; height: 92px; background: #3c3c3c; transform-origin: left center; transform: rotateY(90deg); }
|
|
185
|
+
.screen3d .screen-top { top: -14px; width: 76px; height: 14px; background: #4a4a4a; transform-origin: bottom center; transform: rotateX(90deg); }
|
|
186
|
+
.screen3d .rim {
|
|
187
|
+
position: absolute;
|
|
188
|
+
left: 6px;
|
|
189
|
+
top: 6px;
|
|
190
|
+
width: 64px;
|
|
191
|
+
height: 80px;
|
|
192
|
+
background: var(--plate);
|
|
193
|
+
}
|
|
194
|
+
.screen3d .paper {
|
|
195
|
+
position: absolute;
|
|
196
|
+
left: 14px;
|
|
197
|
+
top: 14px;
|
|
198
|
+
width: 48px;
|
|
199
|
+
height: 64px;
|
|
200
|
+
background: var(--paper);
|
|
201
|
+
}
|
|
202
|
+
.screen3d .glyph {
|
|
203
|
+
position: absolute;
|
|
204
|
+
left: 30px;
|
|
205
|
+
top: 34px;
|
|
206
|
+
width: 24px;
|
|
207
|
+
height: 42px;
|
|
208
|
+
background: var(--ink);
|
|
209
|
+
box-shadow: 0 -10px 0 #111;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.ear-left, .ear-right, .arm-left, .arm-right, .hand-left, .hand-right, .foot-left, .foot-right {
|
|
213
|
+
position: absolute;
|
|
214
|
+
transform-style: preserve-3d;
|
|
215
|
+
background: var(--ink);
|
|
216
|
+
transform: translateZ(18px);
|
|
217
|
+
box-shadow: 8px 0 0 #181818;
|
|
218
|
+
}
|
|
219
|
+
.ear-left { left: 14px; top: 86px; width: 22px; height: 54px; }
|
|
220
|
+
.ear-right { left: 156px; top: 86px; width: 22px; height: 54px; }
|
|
221
|
+
.arm-left { left: 0; top: 140px; width: 42px; height: 14px; }
|
|
222
|
+
.arm-right { left: 150px; top: 140px; width: 42px; height: 14px; }
|
|
223
|
+
.hand-left { left: -8px; top: 130px; width: 24px; height: 24px; }
|
|
224
|
+
.hand-right { left: 176px; top: 130px; width: 24px; height: 24px; }
|
|
225
|
+
.foot-left { left: 58px; top: 184px; width: 30px; height: 30px; }
|
|
226
|
+
.foot-right { left: 116px; top: 184px; width: 30px; height: 30px; }
|
|
227
|
+
|
|
228
|
+
.label {
|
|
229
|
+
position: fixed;
|
|
230
|
+
right: 24px;
|
|
231
|
+
bottom: 22px;
|
|
232
|
+
max-width: 360px;
|
|
233
|
+
font-size: 13px;
|
|
234
|
+
line-height: 1.6;
|
|
235
|
+
color: rgba(0,0,0,.6);
|
|
236
|
+
}
|
|
237
|
+
</style>
|
|
238
|
+
</head>
|
|
239
|
+
<body>
|
|
240
|
+
<div class="toolbar">
|
|
241
|
+
<button id="toggle">busy: on</button>
|
|
242
|
+
<span class="hint">拖动小人;busy 时 3D 转,idle 时停正面</span>
|
|
243
|
+
</div>
|
|
244
|
+
|
|
245
|
+
<div id="wrap" class="pet-wrap busy">
|
|
246
|
+
<div class="floor"></div>
|
|
247
|
+
<div class="ring"></div>
|
|
248
|
+
<div class="axis"></div>
|
|
249
|
+
<div class="pet-3d">
|
|
250
|
+
<div class="solid body3d">
|
|
251
|
+
<i class="front"></i>
|
|
252
|
+
<i class="back"></i>
|
|
253
|
+
<i class="left"></i>
|
|
254
|
+
<i class="right"></i>
|
|
255
|
+
<i class="top"></i>
|
|
256
|
+
<i class="bottom"></i>
|
|
257
|
+
</div>
|
|
258
|
+
<div class="solid screen3d">
|
|
259
|
+
<i class="screen-front"><span class="rim"></span><span class="paper"></span><span class="glyph"></span></i>
|
|
260
|
+
<i class="screen-left"></i>
|
|
261
|
+
<i class="screen-right"></i>
|
|
262
|
+
<i class="screen-top"></i>
|
|
263
|
+
</div>
|
|
264
|
+
<div class="ear-left"></div><div class="ear-right"></div>
|
|
265
|
+
<div class="arm-left"></div><div class="arm-right"></div>
|
|
266
|
+
<div class="hand-left"></div><div class="hand-right"></div>
|
|
267
|
+
<div class="foot-left"></div><div class="foot-right"></div>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
<div class="label">
|
|
272
|
+
Concept preview only. 之后可以把这个 busy/idle 动效迁移回 Electron pet:任意 session busy 就加 <b>.busy</b>,全部 idle 就移除。
|
|
273
|
+
</div>
|
|
274
|
+
|
|
275
|
+
<script>
|
|
276
|
+
const wrap = document.getElementById("wrap")
|
|
277
|
+
const toggle = document.getElementById("toggle")
|
|
278
|
+
let busy = true
|
|
279
|
+
toggle.addEventListener("click", () => {
|
|
280
|
+
busy = !busy
|
|
281
|
+
wrap.classList.toggle("busy", busy)
|
|
282
|
+
toggle.textContent = "busy: " + (busy ? "on" : "off")
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
let dragging = false
|
|
286
|
+
let startX = 0
|
|
287
|
+
let startY = 0
|
|
288
|
+
let originX = 0
|
|
289
|
+
let originY = 0
|
|
290
|
+
|
|
291
|
+
function currentPosition() {
|
|
292
|
+
const rect = wrap.getBoundingClientRect()
|
|
293
|
+
return { x: rect.left, y: rect.top }
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
wrap.addEventListener("pointerdown", (event) => {
|
|
297
|
+
dragging = true
|
|
298
|
+
wrap.classList.add("dragging")
|
|
299
|
+
wrap.setPointerCapture(event.pointerId)
|
|
300
|
+
const pos = currentPosition()
|
|
301
|
+
startX = event.clientX
|
|
302
|
+
startY = event.clientY
|
|
303
|
+
originX = pos.x
|
|
304
|
+
originY = pos.y
|
|
305
|
+
wrap.style.left = originX + "px"
|
|
306
|
+
wrap.style.top = originY + "px"
|
|
307
|
+
wrap.style.transform = "none"
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
wrap.addEventListener("pointermove", (event) => {
|
|
311
|
+
if (!dragging) return
|
|
312
|
+
wrap.style.left = originX + event.clientX - startX + "px"
|
|
313
|
+
wrap.style.top = originY + event.clientY - startY + "px"
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
function stopDrag() {
|
|
317
|
+
dragging = false
|
|
318
|
+
wrap.classList.remove("dragging")
|
|
319
|
+
}
|
|
320
|
+
wrap.addEventListener("pointerup", stopDrag)
|
|
321
|
+
wrap.addEventListener("pointercancel", stopDrag)
|
|
322
|
+
</script>
|
|
323
|
+
</body>
|
|
324
|
+
</html>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256" role="img" aria-labelledby="title desc" shape-rendering="crispEdges">
|
|
2
|
+
<title id="title">Clean pixel opencode pet</title>
|
|
3
|
+
<desc id="desc">A clean pixel-art opencode desktop pet with a dark blocky body, white opencode mark, black center slot, small arms and feet, and seven colorful session balls.</desc>
|
|
4
|
+
|
|
5
|
+
<!-- Transparent background by design: this can be dropped into Electron's transparent BrowserWindow. -->
|
|
6
|
+
<g id="session-balls" data-note="7 colorful balls = 7 opencode/cmux sessions in the original sketch">
|
|
7
|
+
<rect x="56" y="24" width="14" height="14" fill="#ff5d73" />
|
|
8
|
+
<rect x="60" y="26" width="4" height="4" fill="#ffd1d8" />
|
|
9
|
+
|
|
10
|
+
<rect x="90" y="16" width="14" height="14" fill="#ffb020" />
|
|
11
|
+
<rect x="94" y="18" width="4" height="4" fill="#ffe3a3" />
|
|
12
|
+
|
|
13
|
+
<rect x="124" y="20" width="14" height="14" fill="#28c76f" />
|
|
14
|
+
<rect x="128" y="22" width="4" height="4" fill="#b9f6cf" />
|
|
15
|
+
|
|
16
|
+
<rect x="154" y="38" width="14" height="14" fill="#2f8cff" />
|
|
17
|
+
<rect x="158" y="40" width="4" height="4" fill="#c6dcff" />
|
|
18
|
+
|
|
19
|
+
<rect x="178" y="68" width="14" height="14" fill="#8b5cf6" />
|
|
20
|
+
<rect x="182" y="70" width="4" height="4" fill="#dccfff" />
|
|
21
|
+
|
|
22
|
+
<rect x="188" y="104" width="14" height="14" fill="#06b6d4" />
|
|
23
|
+
<rect x="192" y="106" width="4" height="4" fill="#b8f4ff" />
|
|
24
|
+
|
|
25
|
+
<rect x="178" y="140" width="14" height="14" fill="#f97316" />
|
|
26
|
+
<rect x="182" y="142" width="4" height="4" fill="#ffd1a8" />
|
|
27
|
+
</g>
|
|
28
|
+
|
|
29
|
+
<g id="pet-shadow" opacity="0.22">
|
|
30
|
+
<rect x="54" y="206" width="108" height="10" fill="#000000" />
|
|
31
|
+
<rect x="70" y="216" width="76" height="6" fill="#000000" />
|
|
32
|
+
</g>
|
|
33
|
+
|
|
34
|
+
<g id="pet-body" data-style="clean chunky pixel blocks">
|
|
35
|
+
<!-- Feet -->
|
|
36
|
+
<rect x="66" y="184" width="26" height="22" fill="#050505" />
|
|
37
|
+
<rect x="124" y="184" width="26" height="22" fill="#050505" />
|
|
38
|
+
<rect x="72" y="184" width="18" height="8" fill="#242424" />
|
|
39
|
+
<rect x="130" y="184" width="18" height="8" fill="#242424" />
|
|
40
|
+
|
|
41
|
+
<!-- Arms -->
|
|
42
|
+
<rect x="34" y="110" width="18" height="42" fill="#080808" />
|
|
43
|
+
<rect x="44" y="118" width="12" height="30" fill="#242424" />
|
|
44
|
+
<rect x="158" y="110" width="18" height="42" fill="#080808" />
|
|
45
|
+
<rect x="158" y="118" width="12" height="30" fill="#242424" />
|
|
46
|
+
|
|
47
|
+
<!-- Main body silhouette -->
|
|
48
|
+
<rect x="50" y="62" width="112" height="120" fill="#050505" />
|
|
49
|
+
<rect x="42" y="82" width="128" height="80" fill="#050505" />
|
|
50
|
+
<rect x="58" y="54" width="96" height="16" fill="#242424" />
|
|
51
|
+
<rect x="58" y="70" width="96" height="16" fill="#1a1a1a" />
|
|
52
|
+
<rect x="58" y="162" width="96" height="16" fill="#171717" />
|
|
53
|
+
|
|
54
|
+
<!-- Subtle bevel blocks, intentionally sparse to avoid dirty/noisy pixels. -->
|
|
55
|
+
<rect x="58" y="86" width="10" height="66" fill="#2b2b2b" opacity="0.9" />
|
|
56
|
+
<rect x="142" y="86" width="10" height="66" fill="#000000" opacity="0.9" />
|
|
57
|
+
|
|
58
|
+
<!-- Central opencode-inspired mark: white block + black vertical slot. -->
|
|
59
|
+
<rect x="76" y="92" width="64" height="62" fill="#f7f5ef" />
|
|
60
|
+
<rect x="84" y="100" width="48" height="46" fill="#ffffff" />
|
|
61
|
+
<rect x="98" y="108" width="20" height="32" fill="#050505" />
|
|
62
|
+
<rect x="118" y="116" width="8" height="18" fill="#050505" />
|
|
63
|
+
|
|
64
|
+
<!-- Small stacked opencode-like corner blocks. -->
|
|
65
|
+
<rect x="64" y="78" width="18" height="18" fill="#2f2f2f" />
|
|
66
|
+
<rect x="70" y="84" width="14" height="14" fill="#f7f5ef" />
|
|
67
|
+
<rect x="134" y="150" width="18" height="18" fill="#2f2f2f" />
|
|
68
|
+
<rect x="128" y="144" width="14" height="14" fill="#f7f5ef" />
|
|
69
|
+
</g>
|
|
70
|
+
|
|
71
|
+
<g id="caption" fill="#111111" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="10">
|
|
72
|
+
<text x="24" y="238">clean pixel opencode pet · 7 session balls</text>
|
|
73
|
+
</g>
|
|
74
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencube",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A tiny Three.js desktop pet for opencode session activity.",
|
|
5
|
+
"main": "src/main.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
"./server": "./src/plugin-server.cjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"assets",
|
|
11
|
+
"src",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"start": "electron ."
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@electron/get": "^2.0.3",
|
|
19
|
+
"electron": "^39.2.6",
|
|
20
|
+
"extract-zip": "^2.0.1",
|
|
21
|
+
"three": "^0.184.0"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"opencode",
|
|
25
|
+
"opencode-plugin",
|
|
26
|
+
"desktop-pet",
|
|
27
|
+
"electron",
|
|
28
|
+
"threejs"
|
|
29
|
+
]
|
|
30
|
+
}
|