New: Earn 20% as an AgentAlley affiliate. Share your link and earn on every sale you refer. Join now New: Earn 20% as an affiliate. Join now

Build a cursor trail whose spacing stays constant at any

Pointer trail emitter

by MengTo · MIT license · ★ 6,243 on GitHub · updated Sep 23

Pointer trail emitter cover

Build a cursor trail whose spacing stays constant at any hand speed, by emitting motes per unit of distance travelled rather than on a timer, so a flick draws the same continuous ribbon as a crawl instead of breaking into scattered…

---
name: pointer-trail-emitter
description: Build a cursor trail whose spacing stays constant at any hand speed, by emitting motes per unit of distance travelled rather than on a timer, so a flick draws the same continuous ribbon as a crawl instead of breaking into scattered dots. Covers sub-segment placement, the ring-buffer ordering trap, the idle breath a distance emitter needs, anchoring the trail to the screen in a 3-D scene, scaling scatter against the plane it hangs on, coasting instead of stopping dead, touch and reduced-motion fallbacks, and why moving the emitter to a DOM overlay to raise its z-index costs more than it buys. Use for cursor wisps, pointer sparks, embers, magic trails, comet tails, plankton, dust, or any mote trail that must stay legible however fast the hand moves.
---

# Pointer Trail Emitter

Build the emitter yourself when the trail's density has to respond to how fast the hand is moving.

Reach for `add-shader-cursor-trail` or `shaders-cursor-ripples` when you want the packaged WebGPU looks from the Shaders library. Reach for `reveal-hover-effect` when the cursor exposes a second image through a mask. Reach for `ambient-section-particles` when motes fill a section and the pointer only disturbs them. Reach for this when the pointer *lays* them.

The bundled demo keeps the stage intentionally neutral. A plain dark field makes spacing, scatter, and coast easy to judge without a background image competing with the trail. The wisps are dependency-free Vanilla JavaScript rendered through the Canvas 2D API; CSS styles the interface only. There are no shaders, WebGL, or Three.js. Keep the live canvas separate from the interface so the emitter stays testable rather than baked into a composition.

## Emit by distance, not by time

This is the whole mechanism. Accumulate the distance the emitter has moved and spend it in fixed steps:

```js

Overview

Build the emitter yourself when the trail's density has to respond to how fast the hand is moving.

Manual install (npx, ZIP)
Claude Codenpx skills add MengTo/Skills --skill pointer-trail-emitter -g -a claude-code
Claude Code (manual)mkdir -p ~/.claude/skills && curl -sL https://codeload.github.com/MengTo/Skills/tar.gz/a965851e27dc \ | tar -xz -C ~/.claude/skills --strip-components=3 Skills-a965851e27dc/agent-skills/web-design/pointer-trail-emitter
Windows (PowerShell)New-Item -ItemType Directory -Force "$HOME\.claude\skills" | Out-Null; Invoke-WebRequest "https://m.agentalley.io/zip/8f4b9b5e5eb3f64c6562/pointer-trail-emitter.zip" -OutFile "$env:TEMP\pointer-trail-emitter.zip"; Expand-Archive "$env:TEMP\pointer-trail-emitter.zip" -DestinationPath "$HOME\.claude\skills" -Force
Claude.ai / desktopDownload the ZIP and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md10.3 KB
  • agents/1 file · 263 B
  • demo/3 files · 79.0 KB
Read the files here
MengTo/a9658515 files
SKILL.md
Show the full text158 lines

Pointer Trail Emitter

Build the emitter yourself when the trail's density has to respond to how fast the hand is moving.

Reach for add-shader-cursor-trail or shaders-cursor-ripples when you want the packaged WebGPU looks from the Shaders library. Reach for reveal-hover-effect when the cursor exposes a second image through a mask. Reach for ambient-section-particles when motes fill a section and the pointer only disturbs them. Reach for this when the pointer lays them.

The bundled demo keeps the stage intentionally neutral. A plain dark field makes spacing, scatter, and coast easy to judge without a background image competing with the trail. The wisps are dependency-free Vanilla JavaScript rendered through the Canvas 2D API; CSS styles the interface only. There are no shaders, WebGL, or Three.js. Keep the live canvas separate from the interface so the emitter stays testable rather than baked into a composition.

Emit by distance, not by time

This is the whole mechanism. Accumulate the distance the emitter has moved and spend it in fixed steps:

E.acc += moved;
let guard = 0;
while (E.acc >= STEP && guard++ < 14) {
  E.acc -= STEP;
  spawn(/* … */);
}

Spacing along the path is then STEP, whatever the hand is doing, so the trail reads as one continuous ribbon at a crawl and at a flick alike.

Tie emission to a timer instead and spacing becomes proportional to speed — the pointer covers speed × interval between spawns. A flick breaks the line into scattered dots, and a resting hand piles every mote on one spot. That is the failure this prevents, and it is worth building the toggle to see it once.

Measured over one fixed path: distance emission laid 1885 motes slowly and 1738 quickly, a 1.08× spread — the count follows the path. The same two sweeps on a timer laid 2537 and 1545, a 1.64× spread — the count follows the clock.

Cap the loop. A window blur, a tab restore, or a teleporting pointer can hand you a single enormous moved, and without the guard that one frame spawns thousands of motes and stalls.

Place each mote where it is owed

Spawning every mote of a frame at the pointer's current position clumps them at one end of the segment. A flick then reads as a blob with a gap behind it. Lay each at its own distance along the segment:

const t = moved > 1e-6 ? Math.min(1, guard * STEP / moved) : 0;
spawn(E.lx + dx * t, E.ly + dy * t, ang);

Take the ring-buffer slot before advancing it

const i = E.i; E.i = (i + 1) % N;   // correct

Advancing first writes the position into the next slot and the life into this one, so every mote appears where the previous one started. Dense trails hide it; sparse ones show it on every spawn. Symptom to recognise: motes that look one step behind the cursor and pop rather than fade in.

Lag the emitter behind the pointer

Damp the emitter toward the pointer instead of pinning it:

E.x = damp(E.x, px, 16, dt);

A rigidly pinned emitter makes a fast flick look like the trail is welded to the cursor. The lag is what gives the drift its slack.

Anchor the trail to the screen, not the world

For an in-scene 3-D trail, parent the points to the camera and work in camera space. Map the pointer through the frustum's own half-height:

const hh = Math.tan(camera.fov * Math.PI / 360) * D;
const x = nx * hh * camera.aspect, y = ny * hh;

Unprojecting to a world plane instead pins the trail to the set: the moment the rig drifts or parallaxes, the trail swims across the screen rather than staying under the hand.

Use quads or points that ignore depth (depthTest:false, depthWrite:false) and give them their own render order. If the scene has secondary passes — a mirror, a reflection probe — put the trail on its own layer so it never appears in them.

Scale the scatter against the plane it hangs on

Spread is meaningless as an absolute. At a distance of 3.4 units with a 36° camera, the plane the trail hangs on is only about 2.2 units tall — so ±0.03 units of jitter is a thread stitched to the cursor, not a drift.

Compute the plane extent, then express scatter as a fraction of it. The same number that reads as a soft cloud on one camera is a hard line on another.

Let them coast

Damping matters more than initial velocity. At 1 - 1.1 * dt every mote stops within a tenth of a unit of where it spawned and the trail never opens out; halve it and the scatter carries.

Add a slow curl so the drift frays instead of blowing along one straight line, and a small constant rise so it behaves like something buoyant rather than something thrown.

Drop what round motes do not need

A round sprite has no orientation. Remove the per-particle angle attribute and the rotated gl_PointCoord lookup entirely rather than leaving them at zero — that is one attribute, one upload, and several instructions per fragment for a rotation nobody can see.

Keep the motes small: a few pixels of core inside a faint halo. Small sprites are what let the count go up without paying the additive fill a screenful of large ones costs.

Keep a breath when the hand is still

Distance emission means a stationary pointer travels nothing and therefore emits nothing — the trail dies under a resting hand. So add a slow idle emission on a timer purely for that case.

Rarely is the operative word: one every ~0.4s. Emit often from a stationary pointer and it grows a permanent column of smoke up the middle of the frame — which is the timer failure the mechanism exists to avoid, reintroduced by hand.

Numbers

Tuned on a trail hanging 3.4 units from a 36° camera, on a plane ≈2.2 units tall. Scale the spatial values by your own plane extent.

parameter value note
emission step 0.030 units distance between spawns
spawns per frame cap 14 the teleport guard
emitter damping damp(…, 16, dt) the lag behind the pointer
scatter ±0.30 units ≈13% of the plane height
depth jitter ±0.45 units breaks the flat sheet
life 1.45–2.75 s idle motes 2.1–3.4 s
launch velocity −0.09 along travel, ±0.19 lateral against the direction of motion
coast damping 1 − 0.5 * dt halved from 1.1; see above
buoyancy +0.022 · dt
curl sin(t·1.3 + φ)·0.17, cos(t·1.1 + 1.7φ)·0.14 per-mote phase φ
size 0.018–0.050, ×(1 + 0.55u) a mote softens, it does not swell
opacity in over u 0–0.12, out over 0.22–1, ×0.9
count 190 desktop, 90 on a low tier
idle emission every 0.42 s

Do not move it to a DOM overlay to raise its z-index

Nothing inside the WebGL canvas can rise above the page — the canvas is one element at its own stacking tier — so a 2-D overlay canvas looks like the only way to get the layer. It is, and it still is not worth it.

The port costs the post chain: the motes come out as hard points with no bloom, and a wider fainter second copy is not the same thing. Every constant also has to be converted rather than re-picked — px_per_unit = (innerHeight / 2) / (tan(fov / 2) * D), sprite diameter innerHeight * size / D — and rebuilding the look by eye instead of translating it produces a different effect that has to be re-approved.

If the layer is genuinely required, port it as a pure translation and diff the frames against the old build before showing anyone.

State the cost from a profile

The per-mote update is free. A CPU profile of a 190-mote trail showed the update at 0.00% of samples — below the profiler's sampling floor. The cost is entirely additive fill, so the levers are sprite size and count, in that order.

Measure before reporting a regression. A frame-time comparison on this trail once showed a 20–30% p90 rise that turned out to be noise: three runs of identical code gave 226 / 374 / 243 ms. Run it more than once before you believe it.

Lifecycle and reduced motion

  • Gate on matchMedia('(hover: none)'). On touch there is no hover position to follow; park the emitter or drive it from pointermove during a drag only, or a stationary emitter grows a permanent plume.
  • Under prefers-reduced-motion: reduce, render a designed still frame — a composed trail already laid across the frame — rather than hiding it. Keep controls live so they redraw that frame.
  • Pause on document.hidden, reset the time base on resume, clamp dt to ≈1/30 s, and cap DPR at 2.
  • Nothing may depend on the pointer alone. Give the emitter a keyboard path so the effect is complete and operable without a mouse.

Verify

  • The trail is legible on a neutral field before the pointer moves
  • The demo does not rely on background imagery to make the effect look complete
  • Spacing along the path is constant; a flick and a crawl draw the same ribbon
  • Measured, not assumed: mote count over a fixed path barely moves with speed
  • A flick lays motes along the whole segment, not clumped at one end
  • Ring-buffer slot is taken before the index advances
  • 3-D: parented to the camera, and the trail stays under the hand while the rig drifts
  • Scatter is expressed against the plane extent, not as an absolute
  • Motes coast rather than stopping within a fraction of their spawn point
  • A stationary pointer keeps an aura without growing a column
  • No per-particle angle attribute on round sprites
  • Spawn loop is capped against a teleporting pointer
  • Operable from the keyboard; touch path does not plume
  • Reduced motion renders a designed still, not a hidden layer
  • Cost claims came from a profile, and any regression was re-run before it was reported
1---
2name: pointer-trail-emitter
3description: Build a cursor trail whose spacing stays constant at any hand speed, by emitting motes per unit of distance travelled rather than on a timer, so a flick draws the same continuous ribbon as a crawl instead of breaking into scattered dots. Covers sub-segment placement, the ring-buffer ordering trap, the idle breath a distance emitter needs, anchoring the trail to the screen in a 3-D scene, scaling scatter against the plane it hangs on, coasting instead of stopping dead, touch and reduced-motion fallbacks, and why moving the emitter to a DOM overlay to raise its z-index costs more than it buys. Use for cursor wisps, pointer sparks, embers, magic trails, comet tails, plankton, dust, or any mote trail that must stay legible however fast the hand moves.
4---
5 
6# Pointer Trail Emitter
7 
8Build the emitter yourself when the trail's density has to respond to how fast the hand is moving.
9 
10Reach for `add-shader-cursor-trail` or `shaders-cursor-ripples` when you want the packaged WebGPU looks from the Shaders library. Reach for `reveal-hover-effect` when the cursor exposes a second image through a mask. Reach for `ambient-section-particles` when motes fill a section and the pointer only disturbs them. Reach for this when the pointer *lays* them.
11 
12The bundled demo keeps the stage intentionally neutral. A plain dark field makes spacing, scatter, and coast easy to judge without a background image competing with the trail. The wisps are dependency-free Vanilla JavaScript rendered through the Canvas 2D API; CSS styles the interface only. There are no shaders, WebGL, or Three.js. Keep the live canvas separate from the interface so the emitter stays testable rather than baked into a composition.
13 
14## Emit by distance, not by time
15 
16This is the whole mechanism. Accumulate the distance the emitter has moved and spend it in fixed steps:
17 
18```js
19E.acc += moved;
20let guard = 0;
21while (E.acc >= STEP && guard++ < 14) {
22 E.acc -= STEP;
23 spawn(/* … */);
24}
25```
26 
27Spacing along the path is then `STEP`, whatever the hand is doing, so the trail reads as one continuous ribbon at a crawl and at a flick alike.
28 
29Tie emission to a timer instead and spacing becomes proportional to speed — the pointer covers `speed × interval` between spawns. **A flick breaks the line into scattered dots, and a resting hand piles every mote on one spot.** That is the failure this prevents, and it is worth building the toggle to see it once.
30 
31Measured over one fixed path: distance emission laid 1885 motes slowly and 1738 quickly, a 1.08× spread — the count follows the path. The same two sweeps on a timer laid 2537 and 1545, a 1.64× spread — the count follows the clock.
32 
33Cap the loop. A window blur, a tab restore, or a teleporting pointer can hand you a single enormous `moved`, and without the guard that one frame spawns thousands of motes and stalls.
34 
35## Place each mote where it is owed
36 
37Spawning every mote of a frame at the pointer's current position clumps them at one end of the segment. A flick then reads as a blob with a gap behind it. Lay each at its own distance along the segment:
38 
39```js
40const t = moved > 1e-6 ? Math.min(1, guard * STEP / moved) : 0;
41spawn(E.lx + dx * t, E.ly + dy * t, ang);
42```
43 
44## Take the ring-buffer slot before advancing it
45 
46```js
47const i = E.i; E.i = (i + 1) % N; // correct
48```
49 
50Advancing first writes the position into the next slot and the life into this one, so **every mote appears where the previous one started.** Dense trails hide it; sparse ones show it on every spawn. Symptom to recognise: motes that look one step behind the cursor and pop rather than fade in.
51 
52## Lag the emitter behind the pointer
53 
54Damp the emitter toward the pointer instead of pinning it:
55 
56```js
57E.x = damp(E.x, px, 16, dt);
58```
59 
60A rigidly pinned emitter makes a fast flick look like the trail is welded to the cursor. The lag is what gives the drift its slack.
61 
62## Anchor the trail to the screen, not the world
63 
64For an in-scene 3-D trail, parent the points to the **camera** and work in camera space. Map the pointer through the frustum's own half-height:
65 
66```js
67const hh = Math.tan(camera.fov * Math.PI / 360) * D;
68const x = nx * hh * camera.aspect, y = ny * hh;
69```
70 
71Unprojecting to a world plane instead pins the trail to the set: the moment the rig drifts or parallaxes, the trail swims across the screen rather than staying under the hand.
72 
73Use quads or points that ignore depth (`depthTest:false`, `depthWrite:false`) and give them their own render order. If the scene has secondary passes — a mirror, a reflection probe — put the trail on its own layer so it never appears in them.
74 
75## Scale the scatter against the plane it hangs on
76 
77Spread is meaningless as an absolute. At a distance of 3.4 units with a 36° camera, the plane the trail hangs on is only about **2.2 units tall** — so ±0.03 units of jitter is a thread stitched to the cursor, not a drift.
78 
79Compute the plane extent, then express scatter as a fraction of it. The same number that reads as a soft cloud on one camera is a hard line on another.
80 
81## Let them coast
82 
83Damping matters more than initial velocity. At `1 - 1.1 * dt` every mote stops within a tenth of a unit of where it spawned and the trail never opens out; halve it and the scatter carries.
84 
85Add a slow curl so the drift frays instead of blowing along one straight line, and a small constant rise so it behaves like something buoyant rather than something thrown.
86 
87## Drop what round motes do not need
88 
89A round sprite has no orientation. Remove the per-particle angle attribute and the rotated `gl_PointCoord` lookup entirely rather than leaving them at zero — that is one attribute, one upload, and several instructions per fragment for a rotation nobody can see.
90 
91Keep the motes small: a few pixels of core inside a faint halo. Small sprites are what let the count go up without paying the additive fill a screenful of large ones costs.
92 
93## Keep a breath when the hand is still
94 
95Distance emission means a stationary pointer travels nothing and therefore emits nothing — the trail dies under a resting hand. So add a slow idle emission on a timer purely for that case.
96 
97**Rarely** is the operative word: one every ~0.4s. Emit often from a stationary pointer and it grows a permanent column of smoke up the middle of the frame — which is the timer failure the mechanism exists to avoid, reintroduced by hand.
98 
99## Numbers
100 
101Tuned on a trail hanging 3.4 units from a 36° camera, on a plane ≈2.2 units tall. Scale the spatial values by your own plane extent.
102 
103| parameter | value | note |
104| --- | --- | --- |
105| emission step | 0.030 units | distance between spawns |
106| spawns per frame cap | 14 | the teleport guard |
107| emitter damping | `damp(…, 16, dt)` | the lag behind the pointer |
108| scatter | ±0.30 units | ≈13% of the plane height |
109| depth jitter | ±0.45 units | breaks the flat sheet |
110| life | 1.45–2.75 s | idle motes 2.1–3.4 s |
111| launch velocity | −0.09 along travel, ±0.19 lateral | against the direction of motion |
112| coast damping | `1 − 0.5 * dt` | halved from 1.1; see above |
113| buoyancy | +0.022 · dt | |
114| curl | `sin(t·1.3 + φ)·0.17`, `cos(t·1.1 + 1.7φ)·0.14` | per-mote phase φ |
115| size | 0.018–0.050, ×(1 + 0.55u) | a mote softens, it does not swell |
116| opacity | in over u 0–0.12, out over 0.22–1, ×0.9 | |
117| count | 190 desktop, 90 on a low tier | |
118| idle emission | every 0.42 s | |
119 
120## Do not move it to a DOM overlay to raise its z-index
121 
122Nothing inside the WebGL canvas can rise above the page — the canvas is one element at its own stacking tier — so a 2-D overlay canvas looks like the only way to get the layer. It is, and it still is not worth it.
123 
124The port costs the post chain: the motes come out as hard points with no bloom, and a wider fainter second copy is not the same thing. Every constant also has to be converted rather than re-picked — `px_per_unit = (innerHeight / 2) / (tan(fov / 2) * D)`, sprite diameter `innerHeight * size / D` — and rebuilding the look by eye instead of translating it produces a different effect that has to be re-approved.
125 
126If the layer is genuinely required, port it as a pure translation and diff the frames against the old build before showing anyone.
127 
128## State the cost from a profile
129 
130The per-mote update is free. A CPU profile of a 190-mote trail showed the update at **0.00% of samples** — below the profiler's sampling floor. The cost is entirely additive fill, so the levers are sprite size and count, in that order.
131 
132Measure before reporting a regression. A frame-time comparison on this trail once showed a 20–30% p90 rise that turned out to be noise: three runs of *identical* code gave 226 / 374 / 243 ms. Run it more than once before you believe it.
133 
134## Lifecycle and reduced motion
135 
136- Gate on `matchMedia('(hover: none)')`. On touch there is no hover position to follow; park the emitter or drive it from `pointermove` during a drag only, or a stationary emitter grows a permanent plume.
137- Under `prefers-reduced-motion: reduce`, render a **designed still frame** — a composed trail already laid across the frame — rather than hiding it. Keep controls live so they redraw that frame.
138- Pause on `document.hidden`, reset the time base on resume, clamp `dt` to ≈1/30 s, and cap DPR at 2.
139- Nothing may depend on the pointer alone. Give the emitter a keyboard path so the effect is complete and operable without a mouse.
140 
141## Verify
142 
143- [ ] The trail is legible on a neutral field before the pointer moves
144- [ ] The demo does not rely on background imagery to make the effect look complete
145- [ ] Spacing along the path is constant; a flick and a crawl draw the same ribbon
146- [ ] Measured, not assumed: mote count over a fixed path barely moves with speed
147- [ ] A flick lays motes along the whole segment, not clumped at one end
148- [ ] Ring-buffer slot is taken before the index advances
149- [ ] 3-D: parented to the camera, and the trail stays under the hand while the rig drifts
150- [ ] Scatter is expressed against the plane extent, not as an absolute
151- [ ] Motes coast rather than stopping within a fraction of their spawn point
152- [ ] A stationary pointer keeps an aura without growing a column
153- [ ] No per-particle angle attribute on round sprites
154- [ ] Spawn loop is capped against a teleporting pointer
155- [ ] Operable from the keyboard; touch path does not plume
156- [ ] Reduced motion renders a designed still, not a hidden layer
157- [ ] Cost claims came from a profile, and any regression was re-run before it was reported
158 
View all files on GitHub →

Details

Updated
Sep 23, 2026
License
MIT
Stars on the repo
★ 6,243
Checked
Source
MengTo/Skills ↗
Creator
MengTo · 6 listings
View creator

Similar skills

See all →
SkillReverse engineer native, managed, Electron/JavaScriptREAmorluto/rea · by morlutoReverse engineer native, managed, Electron/JavaScript, packaged, firmware, and browser targets with REA. Use shipped-artifact or requested runtime evidence to explain features, compare versions, decompile code, or guide a reconstruction. Skip REA for ordinary source-repository architecture analysis.★ 316k GitHub starsSkillBrainstorms ideas into designs before any creative workBrainstorming Ideas Into Designsobra/superpowers · by obraYou MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation.★ 290k GitHub starsSkillRequires technical rigor and verificationCode Review Receptionobra/superpowers · by obraUse when receiving code review feedback, before implementing suggestions, especially if feedback seems unclear or technically questionable - requires technical rigor and verification, not performative agreement or blind implementation★ 290k GitHub starsSkillDiagnosis loop for hard bugs and performance regressionsDiagnosing bugsmattpocock/skills · by mattpocockDiagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow.★ 267k GitHub starsSkillImplement the result of /to-spec and /to-tickets in codeImplement specmattpocock/skills · by mattpocockImplement the result of /to-spec and /to-tickets in code.★ 267k GitHub starsSkillWriting a PR bodymattpocock/skills · by mattpocockUse when writing a PR body.★ 267k GitHub stars

More from MengTo

SkillApply subtle gradient-border treatments for premium webBorder GradientsMengTo/Skills · by MengToApply subtle gradient-border treatments for premium web surfaces. Use when cards, pricing panels, nav bars, modals, buttons, or hero surfaces need a refined edge highlight without a loud glow.★ 6.2k GitHub starsSkillBuild rich, scroll-controlled real-time Three.js experiencesBuild Three.js Scroll WorldsMengTo/Skills · by MengToBuild rich, scroll-controlled real-time Three.js experiences as one persistent 3D world whose camera, lighting, atmosphere, materials, objects, DOM story, and interactions evolve across authored chapters. Use for 3D scrollytelling, scroll-driven WebGL worlds, camera journeys, interactive portfolios, product stories, exhibitions, explainers, game or film microsites, spatial narratives, and multi-scene websites where native scroll should travel through one continuous place. Not limited to landing pages.★ 6.2k GitHub starsSkillBuild, fix and review character combat animations so theyGame dev: combat animationMengTo/Skills · by MengToBuild, fix and review character combat animations (melee strikes, bow shots, spell casts, skills, monster attacks, whole move sets) so they read like Diablo IV, Baldur's Gate 3 or Elden Ring and never stretch, lock, wring or break an arm, wrist or hand. A written standard with numbered rules, per-frame tests on the real skinned mesh, keys designed from upper-arm, forearm and blade intents, checks from every camera the player sees, two blind critics plus a blind A/B against the last release, and every critic claim verified against full-resolution frames and live-rig numbers. Use when creating or reworking any attack, skill or move set; when the user says arms, hands, wrists, elbows or weapons look stretched, weird, broken or wrong; when they ask for a standard, rules or tests for animations; or when they ask to score animations or get them to N out of 10.★ 6.2k GitHub starsSkillScore a game's combat skills and spells out of 10 with blindGame dev: combat skill polishMengTo/Skills · by MengToScore a game's combat skills and spells out of 10 with blind judges, then raise the weakest to a bar, for timing and readability (does a skill read as itself, does the blow land when it lands) and for art (detail, light, trails, impact, art direction, judged against a reference such as Diablo IV). Covers filming casts on a stopped, stepped clock, contact strips and close-ups, anonymised two-judge rounds, the levers that moved scores (hero props made from a painted concept with image-to-3D, own schedules and keyed moves, painted additive textures, camera-facing ribbons, light outside the body), the traps that cost points, asset and load budgets, and shipping each skill as its own version. Use when the user asks to score, review, improve, polish or rebuild combat skills, spells or attacks; says a skill "doesn't make sense", "looks bad" or should look like another game; names a target score; or starts a "next skill" thread. Project specifics (review hooks, harness settings, where each skill's code lives, scores so far) go in an optional local references/<project>.md next to this skill.★ 6.2k GitHub starsSkillTurn an article, case study, brand narrativeScroll world storytellingMengTo/Skills · by MengToTurn an article, case study, brand narrative, product journey, or long-form story into a cinematic scroll-driven landing page using one of three renderers: scrubbed video, a real-time Three.js world, or semantic HTML/SVG data and typography. Use when the user asks for a scroll world, fly-through landing page, article-to-website transformation, animated planet, data scrollytelling, video-scrubbed page, connected visual journey, or story-led alternative to ordinary stacked sections.★ 6.2k GitHub stars