0
TOOLS#232715a4
It Just Vibes SDK Test Widget
@Owner·deposited 0mo ago·updated 2w ago·60 views
TOOLS#232715a4
It Just Vibes SDK Test Widget
OW
@Owner
60Views
0Comments
0Forks
0Saves
SHARE · REMIX
It Just Vibes SDK Test Widget — a HTML Tools widget by @Owner.
CONTROLS
gameapitest
No comments yet. Be the first!
✦ Remix with AI
SDK in this widget
vibes.onReadyvibes.savevibes.loadvibes.fetchvibes.shared.setvibes.shared.onChange
- localStorage: localStorage detected. Prefer vibes.save/load for per-user persistence.
- raw fetch(): Raw fetch() detected. Prefer vibes.fetch for proxied requests.
Generated prompt
You are helping me modify a vibe-coded widget from itjustvibes.com.
[VIBE CODE: "It Just Vibes SDK Test Widget" by @Owner]
Source: https://itjustvibes.com/Owner/it-just-vibes-sdk-test-widget
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">
<title>It Just Vibes SDK Test Widget</title>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: #111318;
color: #f5f7fb;
}
.wrap {
max-width: 980px;
margin: 0 auto;
padding: 18px;
}
.hero, .card {
background: #191d25;
border: 1px solid #303746;
border-radius: 18px;
padding: 16px;
margin-bottom: 14px;
}
h1, h2 {
margin: 0 0 8px;
}
h1 {
font-size: 28px;
}
h2 {
font-size: 18px;
}
p {
color: #aab3c2;
line-height: 1.45;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
@media (max-width: 760px) {
.grid { grid-template-columns: 1fr; }
}
button {
border: 1px solid #3a4355;
background: #273044;
color: white;
border-radius: 12px;
padding: 10px 12px;
font-weight: 700;
cursor: pointer;
margin: 4px 4px 4px 0;
}
button.primary {
background: #2563eb;
border-color: #60a5fa;
}
button.good {
background: #15803d;
border-color: #4ade80;
}
button.bad {
background: #be123c;
border-color: #fb7185;
}
input {
width: 100%;
background: #0f131b;
color: white;
border: 1px solid #303746;
border-radius: 12px;
padding: 10px;
margin: 6px 0 10px;
}
.result {
background: #0f131b;
border: 1px solid #303746;
border-radius: 12px;
padding: 10px;
min-height: 48px;
white-space: pre-wrap;
overflow: auto;
color: #cbd5e1;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 12px;
}
.status {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 12px;
}
.pill {
background: #0f131b;
border: 1px solid #303746;
border-radius: 999px;
padding: 7px 10px;
color: #cbd5e1;
font-size: 13px;
}
.pass { color: #4ade80; }
.fail { color: #fb7185; }
.warn { color: #fbbf24; }
.big {
font-size: 42px;
font-weight: 900;
}
.check {
padding: 9px;
border: 1px solid #303746;
background: #0f131b;
border-radius: 12px;
margin: 7px 0;
}
</style>
</head>
<body>
<div class="wrap">
<div class="hero">
<h1>It Just Vibes SDK Extension Tester</h1>
<p>
This widget tests SDK readiness, persisted state, proxy fetch, blocked direct fetch,
and multiplayer shared state.
</p>
<div class="status">
<div class="pill">SDK: <span id="sdkStatus" class="warn">checking</span></div>
<div class="pill">Ready: <span id="readyStatus" class="warn">waiting</span></div>
<div class="pill">Shared: <span id="sharedStatus" class="warn">not joined</span></div>
<div class="pill">Viewing now: <span id="activeCount">?</span></div>
</div>
</div>
<div class="card">
<h2>Checklist</h2>
<div id="checklist"></div>
</div>
<div class="grid">
<div class="card">
<h2>Proxy Fetch Test</h2>
<p>Calls an external API through <code>window.vibes.fetch()</code>.</p>
<input id="proxyUrl" value="https://api.weather.gov/">
<button class="primary" id="proxyBtn">Run vibes.fetch()</button>
<div id="proxyResult" class="result">Not run yet.</div>
</div>
<div class="card">
<h2>Direct Fetch Block Test</h2>
<p>This should fail or be blocked.</p>
<input id="blockedUrl" value="http://localhost:3000/">
<button class="bad" id="blockedBtn">Run direct fetch()</button>
<div id="blockedResult" class="result">Not run yet.</div>
</div>
<div class="card">
<h2>Save / Load Test</h2>
<p>Tests <code>vibes.save()</code> and <code>vibes.load()</code>.</p>
<div id="counter" class="big">0</div>
<button class="good" id="counterBtn">Increment and Save</button>
<button id="resetBtn">Reset</button>
<div id="saveResult" class="result">Waiting for SDK.</div>
</div>
<div class="card">
<h2>Multiplayer Shared Test</h2>
<p>Open this widget in two browsers to verify sync.</p>
<input id="roomName" value="sdk-extension-test-room">
<button class="primary" id="joinBtn">Join Room</button>
<input id="sharedMessage" value="Hello from SDK test widget">
<button class="good" id="sendBtn">Send Shared State</button>
<div id="sharedResult" class="result">Not joined.</div>
</div>
</div>
<div class="card">
<h2>Log</h2>
<button class="primary" id="runAllBtn">Run Basic Tests</button>
<button id="clearBtn">Clear Log</button>
<div id="log" class="result">No log entries yet.</div>
</div>
</div>
<script>
(function () {
var STORAGE_KEY = "ijv_sdk_test_widget_v2";
var SHARED_KEY = "sdkTestMessage";
var state = {
counter: 0,
log: [],
checks: {
sdk: "pending",
ready: "pending",
saveLoad: "pending",
proxyFetch: "pending",
directBlocked: "pending",
sharedJoin: "pending",
sharedSet: "pending",
sharedChange: "pending"
}
};
var joined = false;
function el(id) {
return document.getElementById(id);
}
function safeText(value) {
if (value === undefined) return "";
if (value === null) return "";
return String(value);
}
function setText(id, value) {
el(id).textContent = safeText(value);
}
function setHtml(id, value) {
el(id).innerHTML = value;
}
function mark(name, value) {
state.checks[name] = value;
renderChecklist();
saveState();
}
function statusClass(value) {
if (value === "pass") return "pass";
if (value === "fail") return "fail";
return "warn";
}
function renderChecklist() {
var labels = [
["sdk", "window.vibes exists"],
["ready", "window.vibes.onReady completed"],
["saveLoad", "vibes.save() and vibes.load() work"],
["proxyFetch", "vibes.fetch() external API proxy works"],
["directBlocked", "direct fetch to localhost is blocked"],
["sharedJoin", "vibes.shared.join() works"],
["sharedSet", "vibes.shared.set() works"],
["sharedChange", "vibes.shared.onChange() works"]
];
var html = "";
for (var i = 0; i < labels.length; i++) {
var key = labels[i][0];
var label = labels[i][1];
var value = state.checks[key] || "pending";
html += "<div class='check'>" + label + ": <span class='" + statusClass(value) + "'>" + value.toUpperCase() + "</span></div>";
}
setHtml("checklist", html);
}
function addLog(type, message) {
var entry = new Date().toLocaleTimeString() + " [" + type + "] " + message;
state.log.unshift(entry);
if (state.log.length > 60) state.log.length = 60;
renderLog();
saveState();
}
function renderLog() {
if (!state.log.length) {
setText("log", "No log entries yet.");
return;
}
setText("log", state.log.join("\n"));
}
function renderCounter() {
setText("counter", state.counter);
}
async function saveState() {
try {
if (window.vibes && typeof window.vibes.save === "function") {
await window.vibes.save(STORAGE_KEY, state);
} else {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
}
} catch (err) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
} catch (ignore) {}
}
}
async function loadState() {
try {
var saved = null;
if (window.vibes && typeof window.vibes.load === "function") {
saved = await window.vibes.load(STORAGE_KEY);
}
if (!saved) {
var raw = localStorage.getItem(STORAGE_KEY);
if (raw) saved = JSON.parse(raw);
}
if (saved && typeof saved === "object") {
state.counter = saved.counter || 0;
state.log = saved.log || [];
state.checks = saved.checks || state.checks;
}
} catch (err) {
addLog("WARN", "Could not load previous state: " + err.message);
}
renderCounter();
renderChecklist();
renderLog();
}
async function testSaveLoad() {
try {
state.counter = state.counter + 1;
await saveState();
var loaded = null;
if (window.vibes && typeof window.vibes.load === "function") {
loaded = await window.vibes.load(STORAGE_KEY);
}
if (loaded && loaded.counter === state.counter) {
mark("saveLoad", "pass");
setHtml("saveResult", "<span class='pass'>PASS</span> Saved and loaded counter value: " + state.counter);
addLog("PASS", "Save/load worked.");
} else {
mark("saveLoad", "fail");
setHtml("saveResult", "<span class='fail'>FAIL</span> Save/load returned unexpected data.");
addLog("FAIL", "Save/load returned unexpected data.");
}
renderCounter();
} catch (err) {
mark("saveLoad", "fail");
setText("saveResult", "Save/load error: " + err.message);
addLog("FAIL", "Save/load error: " + err.message);
}
}
async function testProxyFetch() {
var url = el("proxyUrl").value;
setText("proxyResult", "Running vibes.fetch against " + url);
try {
if (!window.vibes || typeof window.vibes.fetch !== "function") {
throw new Error("window.vibes.fetch is not available");
}
var response = await window.vibes.fetch(url);
var output = "";
if (response && typeof response.text === "function") {
output = await response.text();
} else {
output = JSON.stringify(response, null, 2);
}
mark("proxyFetch", "pass");
setText("proxyResult", "PASS\n\n" + output.slice(0, 1200));
addLog("PASS", "Proxy fetch succeeded.");
} catch (err) {
mark("proxyFetch", "fail");
setText("proxyResult", "FAIL\n\n" + err.message);
addLog("FAIL", "Proxy fetch failed: " + err.message);
}
}
async function testDirectBlocked() {
var url = el("blockedUrl").value;
setText("blockedResult", "Running direct fetch. This should be blocked.");
try {
var response = await fetch(url);
var body = await response.text();
mark("directBlocked", "fail");
setText("blockedResult", "FAIL\n\nDirect fetch was not blocked.\nStatus: " + response.status + "\n\n" + body.slice(0, 500));
addLog("FAIL", "Direct fetch was not blocked.");
} catch (err) {
mark("directBlocked", "pass");
setText("blockedResult", "PASS\n\nDirect fetch failed or was blocked as expected.\n\n" + err.message);
addLog("PASS", "Direct fetch blocked as expected.");
}
}
function setupSharedListener() {
try {
if (!window.vibes || !window.vibes.shared || typeof window.vibes.shared.onChange !== "function") {
throw new Error("vibes.shared.onChange is not available");
}
window.vibes.shared.onChange(function (data) {
mark("sharedChange", "pass");
setText("sharedResult", "CHANGE RECEIVED\n\n" + JSON.stringify(data, null, 2));
if (data && data.activeUserCount) {
setText("activeCount", data.activeUserCount);
}
if (data && data.viewingNow) {
setText("activeCount", data.viewingNow);
}
addLog("PASS", "Shared state change received.");
});
addLog("PASS", "Shared listener registered.");
} catch (err) {
mark("sharedChange", "fail");
addLog("FAIL", "Shared listener failed: " + err.message);
}
}
async function joinRoom() {
try {
if (!window.vibes || !window.vibes.shared || typeof window.vibes.shared.join !== "function") {
throw new Error("vibes.shared.join is not available");
}
var room = el("roomName").value;
var result = await window.vibes.shared.join(room);
joined = true;
mark("sharedJoin", "pass");
setHtml("sharedStatus", "<span class='pass'>joined</span>");
setText("sharedResult", "Joined room:\n\n" + JSON.stringify(result, null, 2));
addLog("PASS", "Joined shared room: " + room);
setupSharedListener();
} catch (err) {
mark("sharedJoin", "fail");
setHtml("sharedStatus", "<span class='fail'>failed</span>");
setText("sharedResult", "Join failed:\n\n" + err.message);
addLog("FAIL", "Shared join failed: " + err.message);
}
}
async function sendShared() {
try {
if (!joined) {
await joinRoom();
}
if (!window.vibes || !window.vibes.shared || typeof window.vibes.shared.set !== "function") {
throw new Error("vibes.shared.set is not available");
}
var payload = {
message: el("sharedMessage").value,
sentAt: new Date().toISOString(),
random: Math.floor(Math.random() * 100000)
};
var result = await window.vibes.shared.set(SHARED_KEY, payload);
mark("sharedSet", "pass");
setText("sharedResult", "Shared state sent.\n\nOpen a second browser and confirm it updates within 2 seconds.\n\n" + JSON.stringify({ key: SHARED_KEY, payload: payload, result: result }, null, 2));
addLog("PASS", "Shared state sent.");
} catch (err) {
mark("sharedSet", "fail");
setText("sharedResult", "Shared set failed:\n\n" + err.message);
addLog("FAIL", "Shared set failed: " + err.message);
}
}
async function init() {
renderChecklist();
renderCounter();
renderLog();
if (window.vibes) {
mark("sdk", "pass");
setHtml("sdkStatus", "<span class='pass'>detected</span>");
} else {
mark("sdk", "fail");
setHtml("sdkStatus", "<span class='fail'>missing</span>");
}
await loadState();
mark("ready", "pass");
setHtml("readyStatus", "<span class='pass'>ready</span>");
addLog("PASS", "Widget initialized.");
}
el("proxyBtn").addEventListener("click", testProxyFetch);
el("blockedBtn").addEventListener("click", testDirectBlocked);
el("counterBtn").addEventListener("click", testSaveLoad);
el("resetBtn").addEventListener("click", async function () {
state.counter = 0;
renderCounter();
await saveState();
setText("saveResult", "Counter reset and saved.");
addLog("WARN", "Counter reset.");
});
el("joinBtn").addEventListener("click", joinRoom);
el("sendBtn").addEventListener("click", sendShared);
el("runAllBtn").addEventListener("click", async function () {
await testSaveLoad();
await testProxyFetch();
await testDirectBlocked();
});
el("clearBtn").addEventListener("click", async function () {
state.log = [];
renderLog();
await saveState();
});
if (window.vibes && typeof window.vibes.onReady === "function") {
window.vibes.onReady(init);
} else {
init();
}
})();
</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/it-just-vibes-sdk-test-widget */