0
TOOLS#d519aaa1
Tiny Counter
@Owner·deposited 1h ago·updated 1h ago·9 views
TOOLS#d519aaa1
Tiny Counter
OW
@Owner
9Views
0Comments
0Forks
0Saves
SHARE · REMIX
Tiny Counter — a HTML Tools widget by @Owner.
CONTROLS
counterminimalutilityclicker
No comments yet. Be the first!
✦ Remix with AI
SDK in this widgetNo Vibes SDK features detected yet
Generated prompt
You are helping me modify a vibe-coded widget from itjustvibes.com.
[VIBE CODE: "Tiny Counter" by @Owner]
Source: https://itjustvibes.com/Owner/tiny-counter
Type: HTML
--- SOURCE CODE ---
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tiny Counter</title>
<link href="https://fonts.googleapis.com/css2?family=Boogaloo&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #0f0f13;
font-family: 'Boogaloo', cursive;
}
.card {
display: flex;
flex-direction: column;
align-items: center;
gap: 28px;
padding: 48px 56px;
background: #1a1a22;
border-radius: 24px;
border: 1px solid #2e2e3e;
box-shadow: 0 0 60px rgba(120, 80, 255, 0.08);
}
.label {
font-size: 13px;
letter-spacing: 0.25em;
text-transform: uppercase;
color: #555570;
font-family: 'Boogaloo', cursive;
}
#count {
font-size: 100px;
font-weight: 900;
line-height: 1;
min-width: 3ch;
text-align: center;
user-select: none;
font-family: 'Boogaloo', cursive;
text-shadow: 3px 3px 0px #7a0000;
}
#count.bump { animation: bump 0.18s ease-out; }
@keyframes bump {
0% { transform: scale(1); }
50% { transform: scale(1.15); }
100% { transform: scale(1); }
}
.buttons {
display: flex;
gap: 12px;
}
button {
width: 52px;
height: 52px;
border-radius: 14px;
border: 1px solid #2e2e3e;
background: #22222e;
color: #c8c8e0;
font-size: 24px;
font-family: 'Boogaloo', cursive;
cursor: pointer;
transition: background 0.15s, border-color 0.15s, transform 0.1s;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
}
button:hover { background: #2a2a3a; border-color: #5a5aaa; }
button:active { transform: scale(0.92); }
.btn-inc { background: #2a1f4a; border-color: #5a3aaa; color: #a080ff; }
.btn-inc:hover { background: #33285a; border-color: #7c6bff; }
.btn-reset {
width: auto;
padding: 0 18px;
font-size: 13px;
letter-spacing: 0.15em;
color: #444460;
border-color: #222230;
}
.btn-reset:hover { color: #9090b0; border-color: #444460; }
</style>
</head>
<body>
<div class="card">
<div class="label">counter</div>
<div id="count">0</div>
<div class="buttons">
<button class="btn-dec" onclick="change(-1)">−</button>
<button class="btn-inc" onclick="change(1)">+</button>
</div>
<button class="btn-reset" onclick="reset()">RESET</button>
</div>
<script>
let n = 0;
const el = document.getElementById('count');
el.style.setProperty('color', 'red', 'important');
function render() {
el.textContent = n;
el.style.setProperty('color', 'red', 'important');
el.classList.remove('bump');
void el.offsetWidth;
el.classList.add('bump');
}
function change(delta) {
n += delta;
render();
}
function reset() {
n = 0;
el.textContent = n;
el.style.setProperty('color', 'red', 'important');
}
</script>
</body>
</html>
```
[REQUESTED CHANGES]
(no specific request — apply your best judgment)
--- HOW TO RESPOND (READ FIRST) ---
Before writing any code, follow this exact process:
1. **ANALYZE** the widget source code provided above and identify:
a. Which Vibes SDK features it already uses (vibes.save, vibes.load, vibes.shared.join, etc.)
b. Which SDK features would genuinely benefit THIS specific widget — tailored to what it does, not a dump of everything available.
2. **PRESENT A NUMBERED LIST** covering:
- SDK features currently active in this widget
- New SDK features that would concretely improve this widget (be specific: why this widget, what it enables)
3. **WAIT** — do not write any code yet. Reply with your analysis and numbered list, then stop and ask the user which numbered items they want.
4. **IMPLEMENT ONLY** the items the user confirms, plus any explicit change they requested. Do not add unrequested features.
**IMPORTANT — Shared state room names:**
If you add vibes.shared.join(), do NOT use a hardcoded string literal as the room name (e.g. vibes.shared.join("lobby")) unless the user explicitly wants ALL viewers to share one single global state. A hardcoded room name means every person who visits this widget reads and writes the same shared state — it is a global room. For per-user or per-session isolation, derive the room name from a variable (e.g. a user ID, session token, or random value). When in doubt, use vibes.save/vibes.load for per-user persistence instead.
--- VIBES SDK CONTEXT ---
## Vibes SDK Reference
You are building an HTML widget for It Just Vibes (itjustvibes.com). The Vibes SDK is auto-injected — do NOT add a script tag. Just use `window.vibes` (or just `vibes`).
### Setup
Wrap your startup code in `vibes.onReady`:
```js
vibes.onReady(async () => {
const saved = await vibes.load("myKey");
// your widget logic here
});
```
### State (Per-User Persistence)
Every user gets their own isolated state per widget. All methods return Promises.
| Method | Description |
|--------|-------------|
| `await vibes.save(key, value)` | Save JSON-serializable data |
| `await vibes.load(key)` | Load saved data (returns `null` if not found) |
| `await vibes.delete(key)` | Delete a saved key |
| `await vibes.listKeys()` | Get array of all saved key names |
**Key rules:**
- Keys are strings, max 64 characters, alphanumeric + dashes/underscores
- Values must be JSON-serializable (objects, arrays, strings, numbers, booleans)
- Max 100KB per value, 500KB per widget per user, 5MB per user total
- Max 100 keys per widget per user
### Fetch Proxy
Use direct `fetch()` for APIs with permissive CORS headers (`Access-Control-Allow-Origin: *`). Use `vibes.fetch` for APIs without CORS headers (the proxy handles cross-origin requests):
```js
const resp = await vibes.fetch("https://api.example.com/data", {
method: "GET", // GET, POST, PUT, DELETE
headers: {}, // optional headers
body: null, // optional body (string)
timeout: null // optional timeout in ms
});
const data = await resp.json(); // or resp.text()
console.log(resp.status, resp.ok);
```
### Multiplayer (Shared State)
Real-time shared state across all users viewing the same widget.
```js
// Join a room (call once at startup)
await vibes.shared.join("lobby", { persistent: true });
// Set shared state (broadcasts to all users)
await vibes.shared.set("score", { player1: 10, player2: 7 });
// Read shared state (synchronous, returns last known value)
const score = vibes.shared.get("score");
// Listen for changes to a specific key
vibes.shared.onChange("score", (newValue) => {
console.log("Score updated:", newValue);
});
// Listen for any shared state change
vibes.shared.onAny((key, value) => {
console.log(key, "changed to", value);
});
// Get number of connected users
const count = await vibes.shared.getUserCount();
// Leave room
vibes.shared.leave();
// Clear all shared state for this room
await vibes.shared.clear();
```
**Shared state options:**
- `{ persistent: true }` — state survives page reloads (stored server-side)
- Default room name is "__default__" if omitted
### Rules
1. **Do NOT use localStorage, sessionStorage, or window.storage** — they are blocked or undefined in the sandbox. Use `vibes.save`/`vibes.load` instead.
2. **Do NOT add a script tag to import the SDK** — it is auto-injected.
3. **Wrap startup code in `vibes.onReady()`** — the SDK may not be ready immediately.
4. **Await all SDK calls** — every method (except `vibes.shared.get`) returns a Promise.
5. **Do NOT import external JS libraries via script tags** — they will be blocked. Include library code inline or use a CDN link in a `<link>` tag for CSS only.
6. **Keep total code under 80KB** — that is the default widget size limit (your account limit may be higher).
### Rate Limits
| Operation | Limit |
|-----------|-------|
| Writes (save + delete combined) | 30/min |
| Reads (load) | 60/min |
| List keys | 30/min |
| Fetch proxy | Rate limited per widget |
### Error Handling
All SDK methods can reject. Wrap in try/catch:
```js
try {
await vibes.save("key", value);
} catch (err) {
console.error("Save failed:", err.message);
}
```
Fetch proxy errors include `err.code`: `"RATE_LIMITED"`, `"BLOCKED"`, `"FETCH_ERROR"`.
### Data Export
Export rows of data as CSV or Excel directly from your widget.
```js
// Register dataset for the platform's "Export data" button
// AND optionally trigger an immediate download
vibes.exportData(rows, { filename: 'results.csv' })
// rows: Array of arrays (each inner array is one row; first row = headers)
// options.filename: sets the download filename and format (csv or xlsx)
// options.directDownload: false to only register without downloading (default: true)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `filename` | string | `'data.csv'` | Download filename; extension determines format (`.csv` or `.xlsx`) |
| `directDownload` | boolean | `true` | Trigger immediate browser download in addition to registering the dataset |
**Notes:**
- First call registers the dataset so the widget chrome shows an "Export data" button
- Use `.csv` extension for CSV, `.xlsx` for Excel
- CSV injection safety is automatic (formula-starting cells prefixed with `'`)
- Data stays in the browser — no server round-trip
--- FORK & RESUBMIT INSTRUCTION ---
Return the complete, self-contained HTML file with all changes applied.
It should be ready to paste into itjustvibes.com/submit to create a new fork.
Include this comment at the top of the output:
/* Forked from: https://itjustvibes.com/Owner/tiny-counter */