Basic Cohub abilities. Most agents already have these mounted; listed here for reference.
Platform Published by the Neta team.
Official Made by the Neta team.
Verified Reviewed by the Neta team.
Community Shared by a Cohub user. Not reviewed — read SKILL.md before you use it.
pixel-light-switch
Community@xinsong854/pixel-light-switch
Community skill — not reviewed. It was shared by 安诺涅 and has not been checked by Neta. Read SKILL.md below before letting an agent use it.
Use it in Cohub
Paste this into your agent's chat — it fetches the skill and follows it.
Use the skill: pixel-light-switch. Run `npx -y @neta-art/neta-search-cli@latest skills use @xinsong854/pixel-light-switch --via site` and follow what it prints. Read its complete output, redirecting it to a temporary file first if necessary, and resolve relative paths from the skill directory it prints.
Install from a terminal
npx -y @neta-art/neta-search-cli@latest skills use @xinsong854/pixel-light-switch
Summary
Turn one character's two sides into a tiny pixel light switch that flips the whole scene from day to night.
Make a playable page: a pill-shaped switch with a pixel version of your character strolling a chunky 16-bit scene.
Tap the switch or drag the glass knob, and the scene dissolves into night while the character swaps to its other self.
At night the character sits in shadow with only glowing eyes and a different item in hand, still clearly the same person.
Works for sunny/corrupted, day/night, or before/after forms; it speaks the viewer's language and has click sounds with a mute button.
Comes as a published page you can open right away, and can also be packed as a mini app if you ask.
SKILL.md
# Pixel light switch
One character, two forms, one pill-shaped switch. The day form strolls a pixel scene; tap the switch (or drag the glass knob across) and the scene dithers cell by cell into the other form's night, the character swaps for its other self and stands there lit only by rim light, eyes glowing. The page is playable in two seconds, works offline, and can be packed as a Xiaohongshu mini app.
This skill ships a working template (`template/`), the pixel-recovery scripts, and the exact generation prompts. Everything world-specific here is a placeholder: `[character]`, `[day form]`, `[other form]`, `[weapon A]`, `[weapon B]`, `[day place]`, `[night place]`, `[light source]`. Any creator's own character and places drop straight in.
## When to use
- "Make a light switch that flips my character between two forms", "day/night toggle button", "the video where the button switches him to the dark version".
- A character has a normal and a corrupted / awakened / night state and the creator wants it as a small interactive toy rather than a poster.
## When not to use
- One image, no interaction → generate an illustration instead.
- A branching story or dialogue → a roleplay / visual-novel skill.
- A general page with no two-form toggle → a plain web-work skill.
- The two forms are *different characters* (not one character's two states) — that is a pair comparison, not a switch; say so and offer a side-by-side instead.
## Required inputs
| Input | Counts as given when |
|---|---|
| `[character]` | Named, or attached as an image / character card. A bare "make a light switch" does not. |
| The two forms | Described, named, or one screenshot per form. Default if unstated: the character as-is, and the same character with glowing eyes, a fiercer face and a different weapon in hand. |
| Pixel look | A style reference image, or a named look. Default: chunky 16-bit, big head, ~26 px tall. |
Ask once, in one round, only for what is missing. All given → build to delivery without asking again.
## What the user gets (Deliver)
A published **web Work**: a page with the switch, playable immediately, plus the local page source in `works/webs/<slug>/`. Optionally packed as a mini-app zip when the creator asks for one.
1. Build it, publish it (`neta work publish web …`), verify the published page.
2. Hand the Work over on its own line with an **interaction-components** card whose target is `{ "type": "work", "workId": <cohubWorkId from the publish output> }` — the id comes from that output, never guessed.
3. If a mini-app zip was made, hand the zip over as a world-file link as well.
4. Say in one line what you checked and where (local page, published page), and anything you could not check (a real phone, how the sound actually sounds).
## Steps
### 1. Lock the two forms before drawing anything
Write down, in one line each: `[day form]` (hair, clothes, eyes, expression, `[weapon A]`) and `[other form]` (what changes). **The two forms are the same person**: same hair, same clothes, same skin. The differences are: eyes glowing, a fiercer face, and **a different object in hand** (`[weapon A]` → `[weapon B]`). Do not let the model draw the other form as a pale-haired silhouette — that reads as a different character and creators reject it. The black-and-white look comes from the engine's lighting in step 3, not from repainting.
Also fix where the switch lives: the switch's knob covers the left end by day and the right end at night, so `[day place]` should sit centre-right and `[night place]` should have something with a story on the left (a wrecked [vehicle], a lit [building], a [light source]).
### 2. Generate four images
Use `neta generate image` (gpt-image-2.5), always with `--work-title`. Run each call **in the background** and read the result url from the log — an interrupted foreground call can finish, charge, and still lose its result:
```bash
setsid nohup node /mods/neta/neta generate image --work-title "[character] pixel sprites" \
--param size=1536x1024 --param quality=high --param output_format=png \
--image <style reference> --image <character reference> --prompt "…" \
> ./pls-day.log 2>&1 < /dev/null &
```
| Call | Size | Reference images | Gets |
|---|---|---|---|
| 1 | 1536×1024 | style reference + character | 2×3 sheet, use row 1: idle / step-left / step-right of the day form, on flat magenta `#FF00FF` |
| 2 | 1536×512 | **row 1 of call 1** | 1×3 of the other form: idle / `[weapon B]` raised / eyes brightest |
| 3 | 1536×640 | style reference + any layout reference | the day scene, no characters, bottom band left empty |
| 4 | 1536×640 | **call 3** | the same place at night, same layout and horizon, `[light source]`, `[night place]` |
Call 2 is the step that keeps the two forms the same character: pass row 1 of call 1 as the reference and ask for the same hair, clothes and proportions with only the eyes, face and `[weapon B]` changed. Full prompt templates: `references/prompts.md`. Flat magenta beats a transparent background — generated "transparent" PNGs come back as a painted checkerboard.
### 3. Recover the real pixel grid
Generated pixel art is a big picture *of* pixels; the page needs a real low-res grid.
```bash
PYTHONPATH=/workspace/.cache/pylib python3 scripts/pixelize.py <sheet.png> /tmp/pls/sun 2 3 # call 1 (grab row 0)
PYTHONPATH=/workspace/.cache/pylib python3 scripts/pixelize.py <other.png> /tmp/pls/dark 1 3 --p 17 # call 2
PYTHONPATH=/workspace/.cache/pylib python3 scripts/scene.py <day.png> <site>/img/day.png 160
PYTHONPATH=/workspace/.cache/pylib python3 scripts/scene.py <night.png> <site>/img/night.png 200
PYTHONPATH=/workspace/.cache/pylib python3 scripts/atlas.py <site> <six frames in order> # → img/sprites.png + js/sprites.js
```
`pixelize.py` finds the cell size and phase, samples each cell's centre, and drops magenta fringe. Expect frames about 28–34 cells tall at `p≈12–13` for sprites, `p≈17` for the wider 1×3 sheet.
Quantise scenes to **160–200 colours**, not 40: at 40 the metals and lit windows collapse (gold trim turns green, warm windows turn pink). Look at the output before moving on.
`atlas.py` takes the six frames in order — `sun0 sun1 sun2 dark0 dark1 dark2` — lays them side by side and writes anchors measured from the head, so switching frames does not make the character jump sideways. The engine keys off the `sun` / `dark` prefixes: `sun*` is the lit form, `dark*` gets the night lighting.
### 4. Fill in `template/js/config.js`
Copy `template/` into the work, then edit only `config.js` and the three images:
- `text` — UI copy per language (`en`, `zh`, add more). The page picks the viewer's language at runtime; **never hard-code one language**: the day/night labels, the hint line, the loading line, the sound button and the aria labels all come from this table.
- `feet`, `dayStart`, `dayRoam`, `dayStand`, `nightStand` — where it stands. `feet` must sit on the empty band in the scene; `dayRoam` keeps the day form clear of the knob; `nightStand` puts the other form in front of `[night place]`.
- `lightFrom` — which side the night light comes from (`1` right, `-1` left). The rim light and the shadow drag follow it, and the character turns to face it.
- `nightGlowArea` — where the drifting light specks rise (near `[light source]`).
- `nightDarken` — how hard the whole night scene is pushed down. Defaults keep the scene readable with the eyes as the brightest thing.
- `eyeGlow`, `weaponGlow`, the particle colours, `swapBurst`.
### 5. Check it, then publish
```bash
cd <work>/site && python3 -m http.server 8961 # pick a free port: check ss -ltn first
node <skill>/tools/qa.mjs http://localhost:8961/ 390x844
node <skill>/tools/pair.mjs http://localhost:8961/ # day and night sprite side by side, from the pixel buffer
```
`qa.mjs` taps the switch, drags the knob back, presses space, and reports errors and frame time. `pair.mjs` dumps the character out of the 192×80 buffer at both states — **look at that, not at a full-page screenshot**: the eye halo washes the face out in a screenshot and hides whether the lighting reads.
Then: `neta work init web works/webs/<slug>` → `neta work publish web works/webs/<slug> --from works/webs/<slug>/site` → `node <skill>/tools/live.mjs <public page>` to get the content URL → run `qa.mjs` against that URL too.
### 6. Mini app (only when asked)
```bash
node scripts/build_minitool.mjs <work dir> <slug> "<mini app name>"
node <skill>/tools/inapp.mjs http://localhost:<port>/index.html # serve minitool/dist first
```
The build bundles the scripts, inlines the CSS, compresses for Chrome 61, runs the platform audit and writes `mini_tool.json` (`false`: Canvas 2D + WebAudio only). Images stay in `img/`, not `assets/` — the page reads their pixels and a CDN origin would taint the canvas. `platform.js` uses `getWindowInfo` to push the top-right sound button under the host's native buttons. Store art: `node scripts/store-art.mjs <work dir> "<name>" "<one line>"` (`DAY_X` / `NIGHT_X` set where the character stands in the shot).
## How the engine works (`template/js/app.js`)
- **192×80 pixel buffer**, composed every frame, then blown up to the canvas with smoothing off. Size the canvas height from its width — reading the CSS height gives a slightly different ratio and blurs the pixels.
- **Dither transition**: 4×4 Bayer matrix, threshold `t*1.6 - x/W*0.6`, so the night sweeps in left to right behind the knob.
- **Glass knob**: radius 37 cells; each screen pixel refracts through a sphere (about 2× in the middle, squashed at the rim, edge slightly darker), then shadow, rim, elliptical highlight and a bottom reflection arc are drawn over it. Left by day, right at night, with a small overshoot.
- **Night lighting** (`light()`): precomputed per frame — lit colour, glow mask (1 = eyes, 2 = weapon), and both left/right rim strips. Eyes are recognised as "warm, saturated, upper half"; the weapon as "violet-blue". **Change these two tests if `[weapon B]` is another colour.** Switching ramps `L` 0→1.
- **Scene darkening** happens once at load on the night image (gamma, gain, keep some hue, cool tint); stars and specks are damped to match.
- **Behaviour**: the day form strolls and pauses inside `dayRoam`; on switching it stops, pops a "!", and 430 ms later swaps form with a spark burst and one dithered white flash (a solid white flash blows up into a white blob under the knob). At night it walks to `nightStand`, faces the light and cycles three frames.
- **Gestures**: tap toggles; dragging more than 6 px becomes a manual scrub (knob and dissolve follow the finger), releasing past halfway commits; space / enter toggle. `role="switch"` + `aria-checked` are set.
- **Sound** is synthesised live (WebAudio, no files): a click plus a low thump, a falling saw with two triangle overtones going to night, three rising sines coming back. Default on, a button to mute, suspended when the page is hidden.
Reply to the creator in the user's language, including the final handover when the Work goes over, and translate what a script prints instead of pasting it. Text the user sees in the deliverable — captions, hint, loading line, buttons, aria labels — follows the user's language through the `text` table in `config.js`; never hard-code one language.
## When to ask
Ask only when an input in *Required inputs* is missing. Never ask which road to take, which model to use, or how big to make it — those are settled here.
## Out of scope
- No changes to world settings, world slug, or any file outside the work directory and this skill's own folders.
- No deleting pre-existing files; no overwriting another creator's assets.
- No second character or a "battle" between forms — one character, two states.
- No inventing lore text for the character: the caption lines come from the creator's own words or stay neutral.
## Gotchas
- **Generation interrupted costs money.** If the creator sends a new message mid-call the foreground command dies, but the task may already have finished and been charged, and `generate status` then reports `GENERATION_UNAPPLIED` with no way back. Always run generation in the background and read the url from the log.
- A provider `HTTP 404` from the image service is server-side and not charged — retry once unchanged.
- **A busy or refusing model**: on `503` / `429` / capacity, retry the same call once, then fall back to the world's next image model (`NETA_DEFAULT_IMAGE_MODEL` says which) and keep going — do not stop and ask the creator, and never resubmit a call that was already accepted. Out of credits → stop and say so; that is the only case that ends the run.
- `mediaPath` is sometimes missing locally; download the `url` from the result instead.
- Never say the two forms differ by "turning the whole body black": that reads as a different character. Same person, shadowed.
- Laying the night scene out on top of the day scene's composition matters more than its content: keep the horizon and the empty walking band in the same place or the character ends up standing in the sky.
- When the character has no visible face at sprite scale (helmet, mask, back view), the glowing eyes are the whole performance — make them 2 cells wide and the brightest thing on screen.