@clawlabz/clawskin 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.
@@ -0,0 +1,324 @@
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>ClawSkin — Pixel Agent Skin Engine</title>
7
+ <link rel="stylesheet" href="css/style.css">
8
+ <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><text y='28' font-size='28'>🐾</text></svg>">
9
+ </head>
10
+ <body>
11
+ <div class="pixel-grid-overlay"></div>
12
+
13
+ <!-- ═══ Hero ═══ -->
14
+ <section class="hero">
15
+ <div class="hero-badge">🐾 OpenClaw Ecosystem</div>
16
+ <h1 class="hero-title">ClawSkin</h1>
17
+ <p class="hero-subtitle">Give your AI agent a face, an office, and a daily routine.<br>Pixel companion powered by Canvas 2D.</p>
18
+
19
+ <!-- Live Demo -->
20
+ <div class="game-container">
21
+ <canvas id="game-canvas" class="game-canvas" width="720" height="400"></canvas>
22
+ <div class="game-status" id="agent-status">🏢 Office</div>
23
+ </div>
24
+
25
+ <!-- Scene Picker -->
26
+ <div class="controls-bar">
27
+ <div id="scene-picker" style="display:flex;gap:0.5rem;"></div>
28
+ <button class="ctrl-btn" onclick="window._charEditor.toggle(); if(window._charEditor.visible) document.getElementById('character-editor').scrollIntoView({behavior:'smooth',block:'center'})">🎨 Customize</button>
29
+ </div>
30
+ </section>
31
+
32
+ <!-- ═══ Features ═══ -->
33
+ <section class="section">
34
+ <h2 class="section-title">✨ Features</h2>
35
+ <p class="section-desc">Everything you need to bring your AI agent to life.</p>
36
+ <div class="feature-grid">
37
+ <div class="feature-card">
38
+ <div class="feature-icon">🎨</div>
39
+ <div class="feature-title">Character Creator</div>
40
+ <div class="feature-desc">5 skin tones, 5 hairstyles, 5 outfits, accessories, and pets. Mix and match to create your unique pixel agent.</div>
41
+ </div>
42
+ <div class="feature-card">
43
+ <div class="feature-icon">🏠</div>
44
+ <div class="feature-title">Multiple Scenes</div>
45
+ <div class="feature-desc">Cozy office, hacker den, or warm café — each with ambient animations, particles, and mood lighting.</div>
46
+ </div>
47
+ <div class="feature-card">
48
+ <div class="feature-icon">🔄</div>
49
+ <div class="feature-title">Live State Sync</div>
50
+ <div class="feature-desc">Connect to OpenClaw Gateway via WebSocket. Your pixel agent reflects real AI status — typing, thinking, sleeping.</div>
51
+ </div>
52
+ <div class="feature-card">
53
+ <div class="feature-icon">💬</div>
54
+ <div class="feature-title">Speech Bubbles</div>
55
+ <div class="feature-desc">Typewriter-effect dialogue bubbles show what your agent is working on. Thought bubbles for thinking mode.</div>
56
+ </div>
57
+ <div class="feature-card">
58
+ <div class="feature-icon">🐱</div>
59
+ <div class="feature-title">Pixel Pets</div>
60
+ <div class="feature-desc">Add a cat, dog, or robot companion that hangs out with your agent. Because everyone needs a sidekick.</div>
61
+ </div>
62
+ </div>
63
+ </section>
64
+
65
+ <!-- ═══ Customizer ═══ -->
66
+ <section class="section">
67
+ <div>
68
+ <h2 class="section-title">🎨 Customize Your Agent</h2>
69
+ <p class="section-desc">Click options below to customize in real-time. Changes are reflected instantly in the demo above.</p>
70
+ <div id="character-editor"></div>
71
+ </div>
72
+ </section>
73
+
74
+ <!-- ═══ Get Started ═══ -->
75
+ <section class="section">
76
+ <h2 class="section-title">🚀 Get Started</h2>
77
+ <p class="section-desc">Two ways to run ClawSkin locally. Pick what works for you.</p>
78
+ <div class="feature-grid">
79
+ <div class="feature-card" style="border-color:rgba(0,255,136,0.25);">
80
+ <div class="feature-icon">⚡</div>
81
+ <div class="feature-title">npx (Quickest)</div>
82
+ <div class="feature-desc">
83
+ One command, zero install. Starts the app and auto-connects to your local OpenClaw Gateway.<br><br>
84
+ <code style="font-size:0.75rem;background:rgba(0,240,255,0.08);padding:2px 6px;border-radius:4px;">npx @clawlabz/clawskin</code><br><br>
85
+ <strong style="color:var(--accent-green);">Best for:</strong> Quick start, trying it out.
86
+ </div>
87
+ </div>
88
+ <div class="feature-card" style="border-color:rgba(0,240,255,0.25);">
89
+ <div class="feature-icon">💻</div>
90
+ <div class="feature-title">Clone & Run</div>
91
+ <div class="feature-desc">
92
+ Clone the repo for full control. Great if you want to customize scenes or contribute.<br><br>
93
+ <code style="font-size:0.75rem;background:rgba(0,240,255,0.08);padding:2px 6px;border-radius:4px;">git clone → npm start</code><br><br>
94
+ <strong style="color:var(--accent-cyan);">Best for:</strong> Daily use, customization, contributing.
95
+ </div>
96
+ </div>
97
+ </div>
98
+
99
+ <div style="text-align:center;margin-top:2.5rem;">
100
+ <p style="color:var(--text-secondary);font-size:0.85rem;">
101
+ Requires Node.js · Zero npm dependencies · Auto-connects to OpenClaw Gateway
102
+ </p>
103
+ </div>
104
+ </section>
105
+
106
+ <!-- ═══ Requirements ═══ -->
107
+ <section class="section" style="padding-top:0;">
108
+ <h2 class="section-title">📋 What You Need</h2>
109
+ <div class="feature-grid" style="grid-template-columns:repeat(auto-fit,minmax(220px,1fr));">
110
+ <div class="feature-card">
111
+ <div class="feature-icon">🧩</div>
112
+ <div class="feature-title">OpenClaw Gateway</div>
113
+ <div class="feature-desc">Any running OpenClaw instance (v1.0+). <a href="https://docs.openclaw.ai" target="_blank" style="color:var(--accent-cyan);">Install OpenClaw →</a></div>
114
+ </div>
115
+ <div class="feature-card">
116
+ <div class="feature-icon">🔐</div>
117
+ <div class="feature-title">Auth Token</div>
118
+ <div class="feature-desc">If your Gateway has auth enabled, grab the token from <code style="font-size:0.7rem;">~/.openclaw/openclaw.json</code> or run <code style="font-size:0.7rem;">openclaw dashboard</code></div>
119
+ </div>
120
+ </div>
121
+ </section>
122
+
123
+ <!-- ═══ Footer ═══ -->
124
+ <footer class="footer">
125
+ <p>
126
+ <strong style="font-family:'Press Start 2P',monospace;font-size:0.7rem;color:var(--accent-cyan);">ClawSkin</strong>
127
+ — Part of the <a href="https://github.com/clawlabz/openclaw" target="_blank">OpenClaw</a> ecosystem
128
+ </p>
129
+ <p style="margin-top:0.5rem;">
130
+ Built with Canvas 2D · Zero Dependencies · <a href="https://github.com/clawlabz/clawskin" target="_blank">⭐ Star on GitHub</a>
131
+ </p>
132
+ </footer>
133
+
134
+ <!-- ═══ Scripts ═══ -->
135
+ <script src="js/sprites/SpriteGenerator.js"></script>
136
+ <script src="js/character/AnimationManager.js"></script>
137
+ <script src="js/character/BubbleManager.js"></script>
138
+ <script src="js/character/CharacterSprite.js"></script>
139
+ <script src="js/state/DemoMode.js"></script>
140
+ <script src="js/state/AgentStateSync.js"></script>
141
+ <script src="js/scenes/OfficeScene.js"></script>
142
+ <script src="js/scenes/HackerScene.js"></script>
143
+ <script src="js/scenes/CafeScene.js"></script>
144
+ <script src="js/ui/CharacterEditor.js"></script>
145
+ <script src="js/ui/ScenePicker.js"></script>
146
+ <script src="js/app/AgentStateMapper.js"></script>
147
+ <script src="js/app/AgentSlot.js"></script>
148
+ <script src="js/pets/Pet.js"></script>
149
+ <script src="js/pets/PetManager.js"></script>
150
+ <script src="js/game.js"></script>
151
+ <script>
152
+ // ── Rich Demo: 2 agents + desks + 3 pets ──
153
+ document.addEventListener('DOMContentLoaded', () => {
154
+ const canvas = document.getElementById('game-canvas');
155
+ const ctx = canvas.getContext('2d');
156
+ const W = canvas.width, H = canvas.height;
157
+ ctx.imageSmoothingEnabled = false;
158
+
159
+ const spriteGen = new SpriteGenerator();
160
+
161
+ // Scenes
162
+ const scenes = [
163
+ new OfficeScene(canvas, ctx, spriteGen),
164
+ new HackerScene(canvas, ctx, spriteGen),
165
+ new CafeScene(canvas, ctx, spriteGen),
166
+ ];
167
+ scenes.forEach(s => s.init());
168
+ let currentScene = scenes[0];
169
+
170
+ // ── 2 Demo Agents ──
171
+ const agentConfigs = [
172
+ { skinColor: '#FFD5C2', hairType: 0, hairColor: '#333333', outfitType: 'hoodie', outfitColorIdx: 0, accessory: 'glasses' },
173
+ { skinColor: '#C68642', hairType: 2, hairColor: '#1a1a2e', outfitType: 'suit', outfitColorIdx: 2, accessory: 'headphones' },
174
+ ];
175
+ const agentNames = ['Alice', 'Bob'];
176
+
177
+ // Create AgentSlots
178
+ const agents = agentConfigs.map((cfg, i) => {
179
+ // Temporarily override saved configs so demo always looks consistent
180
+ const slot = new AgentSlot({
181
+ agentId: `demo-${i}`,
182
+ label: agentNames[i],
183
+ name: agentNames[i],
184
+ index: i,
185
+ x: 0, y: 0,
186
+ showNameTag: true,
187
+ });
188
+ slot.character.updateConfig(cfg);
189
+ slot._otherAgents = []; // will set after both created
190
+ return slot;
191
+ });
192
+ // Cross-reference for social wandering
193
+ agents.forEach(a => { a._otherAgents = agents; });
194
+
195
+ // ── 3 Pets: cat, dog, bird ──
196
+ const petManager = new PetManager(spriteGen);
197
+ petManager.setSceneBounds(W, H);
198
+ petManager.clearPets();
199
+ petManager.addPet('cat', '#FFFFFF');
200
+ petManager.addPet('dog');
201
+ petManager.addPet('bird', '#4FC3F7');
202
+
203
+ // ── Demo State Cycling ──
204
+ const demoStates = ['idle', 'thinking', 'typing', 'executing', 'browsing', 'idle', 'typing', 'idle'];
205
+ const demoBubbles = [null, 'Analyzing data...', 'Writing code...', null, 'Searching docs...', null, 'Fixing bug...', null];
206
+ const agentTimers = [0, 0];
207
+ const agentStateIdx = [0, 3]; // stagger the two agents
208
+ const stateIntervals = [3500, 4200]; // different pacing
209
+
210
+ function cycleDemoState(agentIdx) {
211
+ const idx = agentStateIdx[agentIdx];
212
+ const state = demoStates[idx];
213
+ const bubble = demoBubbles[idx];
214
+ const slot = agents[agentIdx];
215
+
216
+ slot.stateMapper.currentState = state;
217
+ slot.character.setState(state);
218
+ if (bubble) {
219
+ const type = state === 'thinking' ? 'thought' : 'speech';
220
+ slot.character.showBubble(bubble, type, stateIntervals[agentIdx] - 500);
221
+ }
222
+ agentStateIdx[agentIdx] = (idx + 1) % demoStates.length;
223
+ }
224
+
225
+ // Init first states
226
+ cycleDemoState(0);
227
+ cycleDemoState(1);
228
+
229
+ // ── Render Loop (same pipeline as ClawSkinApp) ──
230
+ let lastTime = performance.now();
231
+
232
+ function loop() {
233
+ const now = performance.now();
234
+ const dt = now - lastTime;
235
+ lastTime = now;
236
+
237
+ // Update
238
+ currentScene.update(dt);
239
+ for (const slot of agents) {
240
+ slot.update(dt);
241
+ }
242
+ petManager.update(dt, agents, currentScene.obstacles || []);
243
+
244
+ // Demo state cycling
245
+ for (let i = 0; i < agents.length; i++) {
246
+ agentTimers[i] += dt;
247
+ if (agentTimers[i] >= stateIntervals[i]) {
248
+ agentTimers[i] = 0;
249
+ cycleDemoState(i);
250
+ }
251
+ }
252
+
253
+ // ── Render (4-phase pipeline) ──
254
+ ctx.clearRect(0, 0, W, H);
255
+ ctx.imageSmoothingEnabled = false;
256
+
257
+ // Layer 0: Scene background
258
+ currentScene.render(ctx);
259
+
260
+ // Workstation layout
261
+ const stations = currentScene.getWorkstations?.(agents.length) || [];
262
+
263
+ // Assign stations to agents
264
+ for (let i = 0; i < agents.length; i++) {
265
+ const s = stations[i];
266
+ if (!s) continue;
267
+ const slot = agents[i];
268
+ slot.station = s;
269
+ slot._scene = currentScene;
270
+ if (s.charScale) slot.character.scale = s.charScale;
271
+ if (!slot.isWandering && !slot._isReturning) {
272
+ slot.character.x = s.charX;
273
+ if (!slot._manualY) slot.character.y = s.charY;
274
+ }
275
+ }
276
+
277
+ // Phase 1: Chairs
278
+ for (const s of stations) {
279
+ currentScene.renderChair(ctx, s);
280
+ }
281
+
282
+ // Phase 2: Characters (Y-sorted)
283
+ const sorted = [...agents].sort((a, b) => a.character.y - b.character.y);
284
+ for (const slot of sorted) {
285
+ slot.render(ctx);
286
+ }
287
+
288
+ // Phase 3: Desks + monitors
289
+ for (let i = 0; i < stations.length; i++) {
290
+ const state = agents[i]?.stateMapper.currentState || 'idle';
291
+ currentScene.renderDesk(ctx, stations[i], state);
292
+ }
293
+
294
+ // Phase 4: Pets
295
+ petManager.render(ctx);
296
+
297
+ // Phase 5: Name tags
298
+ for (const slot of agents) {
299
+ slot.renderNameTag(ctx);
300
+ }
301
+
302
+ requestAnimationFrame(loop);
303
+ }
304
+
305
+ loop();
306
+
307
+ // ── Scene Picker ──
308
+ window._scenePicker = new ScenePicker(scenes, (scene, idx) => {
309
+ currentScene = scenes[idx];
310
+ currentScene.init();
311
+ // Update status label
312
+ document.getElementById('agent-status').textContent = currentScene.label;
313
+ });
314
+ window._scenePicker.render('scene-picker');
315
+
316
+ // ── Character Editor (edits first agent) ──
317
+ window._charEditor = new CharacterEditor(agents[0].character, 'character-editor');
318
+ window._charEditor.onChange = (cfg) => {
319
+ agents[0].updateConfig(cfg);
320
+ };
321
+ });
322
+ </script>
323
+ </body>
324
+ </html>