threejs-awesome-graphics-agent-skills 0.1.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.
- package/.codex-plugin/plugin.json +34 -0
- package/LICENSE +21 -0
- package/README.md +177 -0
- package/bin/threejs-awesome-graphics-agent-skills.mjs +357 -0
- package/package.json +63 -0
- package/skills/threejs-atmosphere-aerial-perspective/SKILL.md +46 -0
- package/skills/threejs-atmosphere-aerial-perspective/agents/openai.yaml +4 -0
- package/skills/threejs-atmosphere-aerial-perspective/examples/lut-aerial-perspective/atmosphere-effect.js +639 -0
- package/skills/threejs-atmosphere-aerial-perspective/references/atmosphere-system-contract.md +213 -0
- package/skills/threejs-bloom/SKILL.md +41 -0
- package/skills/threejs-bloom/agents/openai.yaml +4 -0
- package/skills/threejs-bloom/references/hdr-bloom-system.md +185 -0
- package/skills/threejs-camera-direction/SKILL.md +48 -0
- package/skills/threejs-camera-direction/agents/openai.yaml +4 -0
- package/skills/threejs-camera-direction/references/camera-rig-and-cinematic-systems.md +370 -0
- package/skills/threejs-exposure-color-grading/SKILL.md +39 -0
- package/skills/threejs-exposure-color-grading/agents/openai.yaml +4 -0
- package/skills/threejs-exposure-color-grading/references/scene-referred-color-pipeline.md +205 -0
- package/skills/threejs-image-pipeline/SKILL.md +51 -0
- package/skills/threejs-image-pipeline/agents/openai.yaml +4 -0
- package/skills/threejs-image-pipeline/references/production-image-pipeline.md +195 -0
- package/skills/threejs-procedural-animation/SKILL.md +44 -0
- package/skills/threejs-procedural-animation/agents/openai.yaml +4 -0
- package/skills/threejs-procedural-animation/references/procedural-motion-and-docking-systems.md +362 -0
- package/skills/threejs-procedural-architecture/SKILL.md +54 -0
- package/skills/threejs-procedural-architecture/agents/openai.yaml +4 -0
- package/skills/threejs-procedural-architecture/examples/authored-financial-tower/building-system.js +416 -0
- package/skills/threejs-procedural-architecture/examples/authored-financial-tower/shadow-clipmaps.js +336 -0
- package/skills/threejs-procedural-architecture/references/grammar-and-mesh-compiler.md +509 -0
- package/skills/threejs-procedural-fields/SKILL.md +66 -0
- package/skills/threejs-procedural-fields/agents/openai.yaml +4 -0
- package/skills/threejs-procedural-fields/references/field-stack-recipes.md +232 -0
- package/skills/threejs-procedural-geometry/SKILL.md +50 -0
- package/skills/threejs-procedural-geometry/agents/openai.yaml +4 -0
- package/skills/threejs-procedural-geometry/examples/sculpted-gallery-frame/frame-geometry.js +218 -0
- package/skills/threejs-procedural-geometry/references/profile-sweeps-and-mesh-writers.md +202 -0
- package/skills/threejs-procedural-materials/SKILL.md +65 -0
- package/skills/threejs-procedural-materials/agents/openai.yaml +4 -0
- package/skills/threejs-procedural-materials/references/procedural-pbr-system.md +198 -0
- package/skills/threejs-procedural-planets/SKILL.md +53 -0
- package/skills/threejs-procedural-planets/agents/openai.yaml +4 -0
- package/skills/threejs-procedural-planets/examples/procedural-planet-surface/planet-system.js +417 -0
- package/skills/threejs-procedural-planets/examples/procedural-planet-surface/terrain-field.js +72 -0
- package/skills/threejs-procedural-planets/references/planet-field-and-atmosphere-systems.md +498 -0
- package/skills/threejs-procedural-vegetation/SKILL.md +46 -0
- package/skills/threejs-procedural-vegetation/agents/openai.yaml +4 -0
- package/skills/threejs-procedural-vegetation/examples/structured-ash-growth/ash-preset.js +31 -0
- package/skills/threejs-procedural-vegetation/examples/structured-ash-growth/tree-system.js +477 -0
- package/skills/threejs-procedural-vegetation/references/structured-ash-growth-system.md +314 -0
- package/skills/threejs-procedural-vfx/SKILL.md +43 -0
- package/skills/threejs-procedural-vfx/agents/openai.yaml +4 -0
- package/skills/threejs-procedural-vfx/examples/reentry-plasma/reentry-plasma.js +401 -0
- package/skills/threejs-procedural-vfx/references/procedural-vfx-system.md +218 -0
- package/skills/threejs-raymarched-space-effects/SKILL.md +42 -0
- package/skills/threejs-raymarched-space-effects/agents/openai.yaml +4 -0
- package/skills/threejs-raymarched-space-effects/examples/curved-ray-accretion-volume/curved-ray-effect.js +366 -0
- package/skills/threejs-raymarched-space-effects/references/curved-ray-integrators.md +194 -0
- package/skills/threejs-screen-space-ambient-occlusion/SKILL.md +35 -0
- package/skills/threejs-screen-space-ambient-occlusion/agents/openai.yaml +4 -0
- package/skills/threejs-screen-space-ambient-occlusion/references/gtao-bent-normal-pipeline.md +439 -0
- package/skills/threejs-shadow-systems/SKILL.md +41 -0
- package/skills/threejs-shadow-systems/agents/openai.yaml +4 -0
- package/skills/threejs-shadow-systems/references/cached-clipmap-shadows.md +429 -0
- package/skills/threejs-skill-router/SKILL.md +67 -0
- package/skills/threejs-skill-router/agents/openai.yaml +4 -0
- package/skills/threejs-spectral-ocean/SKILL.md +47 -0
- package/skills/threejs-spectral-ocean/agents/openai.yaml +4 -0
- package/skills/threejs-spectral-ocean/examples/spectral-cascade-ocean/detail-texture.js +100 -0
- package/skills/threejs-spectral-ocean/examples/spectral-cascade-ocean/fft-pipeline.js +284 -0
- package/skills/threejs-spectral-ocean/examples/spectral-cascade-ocean/ocean-material.js +306 -0
- package/skills/threejs-spectral-ocean/examples/spectral-cascade-ocean/ocean-system.js +318 -0
- package/skills/threejs-spectral-ocean/examples/spectral-cascade-ocean/spectrum.js +245 -0
- package/skills/threejs-spectral-ocean/references/spectral-cascade-ocean-system.md +471 -0
- package/skills/threejs-temporal-surfaces/SKILL.md +44 -0
- package/skills/threejs-temporal-surfaces/agents/openai.yaml +4 -0
- package/skills/threejs-temporal-surfaces/examples/touch-history-frost/frost-surface-effect.js +671 -0
- package/skills/threejs-temporal-surfaces/references/ping-pong-accumulation.md +207 -0
- package/skills/threejs-visual-validation/SKILL.md +48 -0
- package/skills/threejs-visual-validation/agents/openai.yaml +4 -0
- package/skills/threejs-visual-validation/references/graphics-validation-protocol.md +406 -0
- package/skills/threejs-volumetric-clouds/SKILL.md +51 -0
- package/skills/threejs-volumetric-clouds/agents/openai.yaml +4 -0
- package/skills/threejs-volumetric-clouds/examples/weather-volume-clouds/cloud-effect.js +164 -0
- package/skills/threejs-volumetric-clouds/examples/weather-volume-clouds/cloud-system.js +680 -0
- package/skills/threejs-volumetric-clouds/references/weather-volume-and-reconstruction.md +579 -0
- package/skills/threejs-water-optics/SKILL.md +47 -0
- package/skills/threejs-water-optics/agents/openai.yaml +4 -0
- package/skills/threejs-water-optics/examples/analytic-wave-optics/water-system.js +314 -0
- package/skills/threejs-water-optics/references/water-surface-system.md +193 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "threejs-awesome-graphics-agent-skills",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Expert agent skills for creating exceptional Three.js graphics.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Scott"
|
|
7
|
+
},
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"threejs",
|
|
11
|
+
"webgl",
|
|
12
|
+
"webgpu",
|
|
13
|
+
"procedural-graphics",
|
|
14
|
+
"shaders",
|
|
15
|
+
"volumetrics"
|
|
16
|
+
],
|
|
17
|
+
"skills": "./skills/",
|
|
18
|
+
"interface": {
|
|
19
|
+
"displayName": "Three.js Awesome Graphics Agent Skills",
|
|
20
|
+
"shortDescription": "Expert procedural Three.js graphics systems",
|
|
21
|
+
"longDescription": "Atomic expertise for procedural geometry, coherent materials, advanced shaders, atmosphere, volumetrics, shadows, temporal effects, and deliberate final-image pipelines in Three.js.",
|
|
22
|
+
"developerName": "Scott",
|
|
23
|
+
"category": "Developer Tools",
|
|
24
|
+
"capabilities": [
|
|
25
|
+
"Interactive",
|
|
26
|
+
"Write"
|
|
27
|
+
],
|
|
28
|
+
"defaultPrompt": [
|
|
29
|
+
"Decompose an ambitious Three.js visual into expert systems.",
|
|
30
|
+
"Build a coherent procedural material and geometry pipeline.",
|
|
31
|
+
"Audit this scene's graphics mechanisms and visual evidence."
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Scott Sun
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Three.js Awesome Graphics Agent Skills
|
|
2
|
+
|
|
3
|
+
This is a Three.js agent skill pack for producing awesome graphics.
|
|
4
|
+
|
|
5
|
+
It includes mesh design, lighting, PBR materials, textures, shaders, TSL/WebGPU, GLSL, post-processing, realism, stylization, particles, procedural visuals, color management, tone mapping, etc. Graphics excellence is the **main focus** of this skill pack, with sophisticated design aesthetics, philosophy, ergonomics, sensibility, taste
|
|
6
|
+
|
|
7
|
+
This is NOT a three.js API cheat sheet, it skips basic 3D production fundamentals (any decent LLM already has that internal knowledge), it also skips three.js API technicalities (just look up docs or use existing API oriented agent skills). This skill pack is meant for agent to produce stunning 3D scenes and graphics that transcend simple demos. It brings the sophistication of good graphics and eliminates cheap effort.
|
|
8
|
+
|
|
9
|
+
I aim to continuously update this skill pack as more three.js projects with awesome graphics emerge. I hope this skill pack can help anyone build awesome scenes and games with out of the box sophisticated graphics.
|
|
10
|
+
|
|
11
|
+
## Operating model
|
|
12
|
+
|
|
13
|
+
Load `$threejs-skill-router` for a broad visual task, then load only the atomic systems the work actually needs.
|
|
14
|
+
|
|
15
|
+
Every graphics system is expected to expose:
|
|
16
|
+
|
|
17
|
+
- deterministic or reproducible inputs;
|
|
18
|
+
- named controlling fields and perceptual parameters;
|
|
19
|
+
- diagnostic outputs;
|
|
20
|
+
- scale, distance, and temporal stability rules;
|
|
21
|
+
- an intentional mechanism-backed quality or resolution tier when the system defines one;
|
|
22
|
+
- a no-post baseline that still reads.
|
|
23
|
+
|
|
24
|
+
## Skills
|
|
25
|
+
|
|
26
|
+
| Skill | Expertise |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| `threejs-skill-router` | Decompose a visual target into the smallest relevant expert systems. |
|
|
29
|
+
| `threejs-camera-direction` | Authored lenses and shots, chase/side/orbit rigs, body-relative frames, handoffs, pointer look, floating origins. |
|
|
30
|
+
| `threejs-procedural-animation` | Analytic timelines, gravity turns, staging, rotating-frame docking, springs, quaternion alignment, debris motion. |
|
|
31
|
+
| `threejs-procedural-fields` | Shared scalar/vector fields, frequency bands, domain warping, causal masks, procedural normals. |
|
|
32
|
+
| `threejs-procedural-materials` | Atlas filtering, specular AA, planetary materials, terrain wetness, frame PBR, per-instance dissolve. |
|
|
33
|
+
| `threejs-procedural-geometry` | Sculpted frame rails, branch rings, semantic mesh writers, UV density, material groups. |
|
|
34
|
+
| `threejs-procedural-vegetation` | Growth hierarchies, branch-ring geometry, stratified children, foliage normals, wind. |
|
|
35
|
+
| `threejs-procedural-architecture` | Massing and façade grammars, exposed-edge analysis, modules, material-slot compilation. |
|
|
36
|
+
| `threejs-procedural-planets` | Spherical terrain, ridges, craters, biomes, procedural normals, altitude filtering. |
|
|
37
|
+
| `threejs-spectral-ocean` | Validated FFT synthesis, spectral cascades, choppy derivatives, Jacobian foam, ocean shading. |
|
|
38
|
+
| `threejs-water-optics` | Shared analytic waves/normals, heuristic refraction, fallback absorption, reflection, crest foam. |
|
|
39
|
+
| `threejs-atmosphere-aerial-perspective` | Shared Rayleigh/Mie atmosphere, sky, shell/post handoff, depth-based scattering. |
|
|
40
|
+
| `threejs-volumetric-clouds` | Weather-shaped density, bounded raymarching, cloud lighting, history, cloud shadows. |
|
|
41
|
+
| `threejs-raymarched-space-effects` | Curved-ray integration, black holes, accretion disks, wormholes, bounded quality. |
|
|
42
|
+
| `threejs-procedural-vfx` | Reentry shells/wakes, instanced sparks, dissolving debris, dense pools, HDR hierarchy. |
|
|
43
|
+
| `threejs-temporal-surfaces` | Persistent touch history, reduced blur, frost composite, and normal refraction. |
|
|
44
|
+
| `threejs-shadow-systems` | Stable cascades and cached clipmap shadows with update budgets and invalidation. |
|
|
45
|
+
| `threejs-screen-space-ambient-occlusion` | GTAO-style horizon sampling, bent normals, bilateral and temporal reconstruction. |
|
|
46
|
+
| `threejs-bloom` | HDR extraction, multi-scale filtering, selective contribution, exposure coupling. |
|
|
47
|
+
| `threejs-exposure-color-grading` | Encoded luminance metering, asymmetric adaptation, tone mapping, generated 3D LUT. |
|
|
48
|
+
| `threejs-image-pipeline` | Shared render-signal ownership and ordering across multiple image-space systems. |
|
|
49
|
+
| `threejs-visual-validation` | Fixed-view captures, diagnostic mosaics, seed/scale sweeps, temporal and GPU evidence. |
|
|
50
|
+
|
|
51
|
+
## Examples of use
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
Use $threejs-skill-router to decompose and build a procedural ocean planet
|
|
55
|
+
with a ground-to-orbit camera.
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
Use $threejs-procedural-vegetation to build a deterministic tree species
|
|
60
|
+
with coherent branching, bark scale, foliage normals, and hierarchical wind.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
Use $threejs-camera-direction and $threejs-procedural-animation to stage a
|
|
65
|
+
planet-relative ship approach with an authored side-camera handoff and docking.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
Use $threejs-bloom to diagnose the HDR signal and tune bloom without making
|
|
70
|
+
the glow carry the underlying form.
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
Use $threejs-visual-validation to produce a deterministic evidence set for
|
|
75
|
+
this procedural material across camera distance, seeds, motion, and quality tiers.
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Install
|
|
79
|
+
|
|
80
|
+
The published package and installer command are `threejs-awesome-graphics-agent-skills`.
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
# User-wide installation
|
|
84
|
+
npx threejs-awesome-graphics-agent-skills install --agent codex
|
|
85
|
+
npx threejs-awesome-graphics-agent-skills install --agent claude-code
|
|
86
|
+
npx threejs-awesome-graphics-agent-skills install --agent cursor
|
|
87
|
+
|
|
88
|
+
# Project installation
|
|
89
|
+
npx threejs-awesome-graphics-agent-skills install --agent github-copilot --scope project
|
|
90
|
+
|
|
91
|
+
# Any custom-built agent
|
|
92
|
+
npx threejs-awesome-graphics-agent-skills install --agent custom --path ~/.my-agent/skills
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Supported targets:
|
|
96
|
+
|
|
97
|
+
| Target | User scope | Project scope |
|
|
98
|
+
| --- | --- | --- |
|
|
99
|
+
| `universal` | `~/.agents/skills` | `.agents/skills` |
|
|
100
|
+
| `codex` | `~/.agents/skills` | `.agents/skills` |
|
|
101
|
+
| `claude-code` | `~/.claude/skills` | `.claude/skills` |
|
|
102
|
+
| `cursor` | `~/.cursor/skills` | `.cursor/skills` |
|
|
103
|
+
| `github-copilot` | `~/.copilot/skills` | `.github/skills` |
|
|
104
|
+
| `gemini-cli` | `~/.gemini/skills` | `.gemini/skills` |
|
|
105
|
+
| `windsurf` | `~/.codeium/windsurf/skills` | `.windsurf/skills` |
|
|
106
|
+
| `custom` | exact `--path` | exact `--path` |
|
|
107
|
+
|
|
108
|
+
Each installation contains the complete pack so its router can reference every atomic skill. Use `--force` to replace an existing installation and `--dry-run` to inspect changes.
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
npx threejs-awesome-graphics-agent-skills uninstall --agent cursor
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Development
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
npm run validate
|
|
118
|
+
npm test
|
|
119
|
+
npm run check:freshness
|
|
120
|
+
npm pack --dry-run
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Inspect every included graphics example from one development surface:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
npm run dev:examples
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The gallery discovers development adapters corresponding to skill examples
|
|
130
|
+
automatically and provides single-example and live-overview modes, viewport/DPR
|
|
131
|
+
controls, pause/time controls, debug-mode routing, standalone launch, runtime
|
|
132
|
+
metrics, and canvas capture. It is repository tooling and is not installed as
|
|
133
|
+
an agent skill.
|
|
134
|
+
|
|
135
|
+
Current accepted inspection surfaces:
|
|
136
|
+
|
|
137
|
+
- [Atmosphere and aerial perspective](http://127.0.0.1:4173/?example=threejs-atmosphere-aerial-perspective%2Flut-aerial-perspective)
|
|
138
|
+
— precomputed sky radiance, sun transmittance, and depth-aware segment
|
|
139
|
+
scattering;
|
|
140
|
+
- [Sculpted gallery frame](http://127.0.0.1:4173/?example=threejs-procedural-geometry%2Fsculpted-gallery-frame)
|
|
141
|
+
— profile-swept mesh, authored frame PBR, grazing lights, shadows, and
|
|
142
|
+
selective bloom;
|
|
143
|
+
- [Ash growth system](http://127.0.0.1:4173/?example=threejs-procedural-vegetation%2Fstructured-ash-growth)
|
|
144
|
+
— species-specific hierarchy, branch geometry, foliage, wind, and meadow;
|
|
145
|
+
- [Curved-ray accretion volume](http://127.0.0.1:4173/?example=threejs-raymarched-space-effects%2Fcurved-ray-accretion-volume)
|
|
146
|
+
— bounded ray steering, accretion density, transmittance, and bent
|
|
147
|
+
environment lookup;
|
|
148
|
+
- [Spectral cascade ocean](http://127.0.0.1:4173/?example=threejs-spectral-ocean%2Fspectral-cascade-ocean)
|
|
149
|
+
— directional spectra, staged inverse FFT, choppy displacement, and
|
|
150
|
+
persistent Jacobian foam;
|
|
151
|
+
- [Procedural planet surface](http://127.0.0.1:4173/?example=threejs-procedural-planets%2Fprocedural-planet-surface)
|
|
152
|
+
— coupled displacement, geological fields, biome masks, water, and
|
|
153
|
+
altitude-filtered material detail;
|
|
154
|
+
- [Authored financial tower](http://127.0.0.1:4173/?example=threejs-procedural-architecture%2Fauthored-financial-tower)
|
|
155
|
+
— semantic massing, façade grammar, grouped mesh emission, and cached
|
|
156
|
+
clipmap shadows;
|
|
157
|
+
- [Analytic wave optics](http://127.0.0.1:4173/?example=threejs-water-optics%2Fanalytic-wave-optics)
|
|
158
|
+
— shared displaced waves and normals, filtered microstructure, Fresnel,
|
|
159
|
+
refraction, absorption, and crest response;
|
|
160
|
+
- [Weather volume clouds](http://127.0.0.1:4173/?example=threejs-volumetric-clouds%2Fweather-volume-clouds)
|
|
161
|
+
— packed weather channels, profile-shaped density, bounded integration,
|
|
162
|
+
directional lighting, and temporal reconstruction;
|
|
163
|
+
- [Reentry plasma](http://127.0.0.1:4173/?example=threejs-procedural-vfx%2Freentry-plasma)
|
|
164
|
+
— closed layered wake shells, flow deformation, advected filaments, and
|
|
165
|
+
additive thermal emission;
|
|
166
|
+
- [Touch-history frost](http://127.0.0.1:4173/?example=threejs-temporal-surfaces%2Ftouch-history-frost)
|
|
167
|
+
— persistent interaction history, static crystalline fields, reduced blur,
|
|
168
|
+
and two-scale refraction.
|
|
169
|
+
|
|
170
|
+
Generate deterministic captures and a contact sheet:
|
|
171
|
+
|
|
172
|
+
```sh
|
|
173
|
+
npm run capture:examples
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The gallery contract is documented in
|
|
177
|
+
[`dev/example-gallery/README.md`](dev/example-gallery/README.md).
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
cp,
|
|
5
|
+
mkdir,
|
|
6
|
+
readFile,
|
|
7
|
+
readdir,
|
|
8
|
+
rename,
|
|
9
|
+
rm,
|
|
10
|
+
stat,
|
|
11
|
+
writeFile,
|
|
12
|
+
} from "node:fs/promises";
|
|
13
|
+
import os from "node:os";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import process from "node:process";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
|
|
18
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
19
|
+
const skillsSource = path.join(packageRoot, "skills");
|
|
20
|
+
const packageJson = JSON.parse(
|
|
21
|
+
await readFile(path.join(packageRoot, "package.json"), "utf8"),
|
|
22
|
+
);
|
|
23
|
+
const manifestName = ".threejs-awesome-graphics-agent-skills.json";
|
|
24
|
+
|
|
25
|
+
const targets = {
|
|
26
|
+
universal: {
|
|
27
|
+
label: "Open Agent Skills",
|
|
28
|
+
project: [".agents", "skills"],
|
|
29
|
+
user: [".agents", "skills"],
|
|
30
|
+
},
|
|
31
|
+
codex: {
|
|
32
|
+
label: "OpenAI Codex",
|
|
33
|
+
project: [".agents", "skills"],
|
|
34
|
+
user: [".agents", "skills"],
|
|
35
|
+
},
|
|
36
|
+
"claude-code": {
|
|
37
|
+
label: "Claude Code",
|
|
38
|
+
project: [".claude", "skills"],
|
|
39
|
+
user: [".claude", "skills"],
|
|
40
|
+
},
|
|
41
|
+
cursor: {
|
|
42
|
+
label: "Cursor",
|
|
43
|
+
project: [".cursor", "skills"],
|
|
44
|
+
user: [".cursor", "skills"],
|
|
45
|
+
},
|
|
46
|
+
"github-copilot": {
|
|
47
|
+
label: "GitHub Copilot",
|
|
48
|
+
project: [".github", "skills"],
|
|
49
|
+
user: [".copilot", "skills"],
|
|
50
|
+
},
|
|
51
|
+
"gemini-cli": {
|
|
52
|
+
label: "Gemini CLI",
|
|
53
|
+
project: [".gemini", "skills"],
|
|
54
|
+
user: [".gemini", "skills"],
|
|
55
|
+
},
|
|
56
|
+
windsurf: {
|
|
57
|
+
label: "Windsurf / Devin Desktop",
|
|
58
|
+
project: [".windsurf", "skills"],
|
|
59
|
+
user: [".codeium", "windsurf", "skills"],
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const aliases = {
|
|
64
|
+
agents: "universal",
|
|
65
|
+
claude: "claude-code",
|
|
66
|
+
copilot: "github-copilot",
|
|
67
|
+
gemini: "gemini-cli",
|
|
68
|
+
devin: "windsurf",
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
function printHelp() {
|
|
72
|
+
console.log(`Three.js Awesome Graphics Agent Skills ${packageJson.version}
|
|
73
|
+
|
|
74
|
+
Usage:
|
|
75
|
+
threejs-awesome-graphics-agent-skills list
|
|
76
|
+
threejs-awesome-graphics-agent-skills install --agent <target> [options]
|
|
77
|
+
threejs-awesome-graphics-agent-skills uninstall --agent <target> [options]
|
|
78
|
+
|
|
79
|
+
Targets:
|
|
80
|
+
universal, codex, claude-code, cursor, github-copilot, gemini-cli, windsurf
|
|
81
|
+
custom (requires --path)
|
|
82
|
+
|
|
83
|
+
Options:
|
|
84
|
+
--scope <user|project> Installation scope (default: user)
|
|
85
|
+
--path <directory> Exact skills root; required for custom agents
|
|
86
|
+
--project-dir <path> Project root for project-scoped installs
|
|
87
|
+
--force Replace existing installed skill directories
|
|
88
|
+
--dry-run Print actions without writing
|
|
89
|
+
--version Print package version
|
|
90
|
+
--help Show this help
|
|
91
|
+
|
|
92
|
+
Examples:
|
|
93
|
+
npx threejs-awesome-graphics-agent-skills install --agent codex
|
|
94
|
+
npx threejs-awesome-graphics-agent-skills install --agent claude-code --scope project
|
|
95
|
+
npx threejs-awesome-graphics-agent-skills install --agent cursor,copilot --force
|
|
96
|
+
npx threejs-awesome-graphics-agent-skills install --agent custom --path ~/.my-agent/skills
|
|
97
|
+
`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function parseArgs(argv) {
|
|
101
|
+
const [rawCommand = "help", ...rest] = argv;
|
|
102
|
+
const command = rawCommand === "--help" || rawCommand === "-h"
|
|
103
|
+
? "help"
|
|
104
|
+
: rawCommand === "--version" || rawCommand === "-v"
|
|
105
|
+
? "version"
|
|
106
|
+
: rawCommand;
|
|
107
|
+
const options = {
|
|
108
|
+
command,
|
|
109
|
+
scope: "user",
|
|
110
|
+
agents: [],
|
|
111
|
+
force: false,
|
|
112
|
+
dryRun: false,
|
|
113
|
+
projectDir: process.cwd(),
|
|
114
|
+
customPath: null,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
118
|
+
const argument = rest[index];
|
|
119
|
+
const value = rest[index + 1];
|
|
120
|
+
if (argument === "--agent" && value) {
|
|
121
|
+
options.agents.push(...value.split(",").filter(Boolean));
|
|
122
|
+
index += 1;
|
|
123
|
+
} else if (argument === "--scope" && value) {
|
|
124
|
+
options.scope = value;
|
|
125
|
+
index += 1;
|
|
126
|
+
} else if (argument === "--path" && value) {
|
|
127
|
+
options.customPath = value;
|
|
128
|
+
index += 1;
|
|
129
|
+
} else if (argument === "--project-dir" && value) {
|
|
130
|
+
options.projectDir = value;
|
|
131
|
+
index += 1;
|
|
132
|
+
} else if (argument === "--force") {
|
|
133
|
+
options.force = true;
|
|
134
|
+
} else if (argument === "--dry-run") {
|
|
135
|
+
options.dryRun = true;
|
|
136
|
+
} else if (argument === "--help" || argument === "-h") {
|
|
137
|
+
options.command = "help";
|
|
138
|
+
} else {
|
|
139
|
+
throw new Error(`Unknown or incomplete option: ${argument}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return options;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function pathExists(targetPath) {
|
|
147
|
+
try {
|
|
148
|
+
await stat(targetPath);
|
|
149
|
+
return true;
|
|
150
|
+
} catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function availableSkills() {
|
|
156
|
+
const entries = await readdir(skillsSource, { withFileTypes: true });
|
|
157
|
+
return entries
|
|
158
|
+
.filter((entry) => entry.isDirectory())
|
|
159
|
+
.map((entry) => entry.name)
|
|
160
|
+
.sort();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function normalizeAgent(agent) {
|
|
164
|
+
const normalized = aliases[agent] ?? agent;
|
|
165
|
+
if (normalized !== "custom" && !targets[normalized]) {
|
|
166
|
+
throw new Error(`Unsupported agent target: ${agent}`);
|
|
167
|
+
}
|
|
168
|
+
return normalized;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function resolveDestination(agent, options) {
|
|
172
|
+
if (agent === "custom") {
|
|
173
|
+
if (!options.customPath) {
|
|
174
|
+
throw new Error("The custom target requires --path <skills-directory>.");
|
|
175
|
+
}
|
|
176
|
+
return path.resolve(options.customPath.replace(/^~(?=$|\/|\\)/, os.homedir()));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!["user", "project"].includes(options.scope)) {
|
|
180
|
+
throw new Error("--scope must be user or project.");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const base = options.scope === "user"
|
|
184
|
+
? os.homedir()
|
|
185
|
+
: path.resolve(options.projectDir);
|
|
186
|
+
return path.join(base, ...targets[agent][options.scope]);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function readInstallManifest(destination) {
|
|
190
|
+
try {
|
|
191
|
+
const manifest = JSON.parse(
|
|
192
|
+
await readFile(path.join(destination, manifestName), "utf8"),
|
|
193
|
+
);
|
|
194
|
+
if (
|
|
195
|
+
manifest.package !== packageJson.name ||
|
|
196
|
+
!Array.isArray(manifest.skills) ||
|
|
197
|
+
manifest.skills.some(
|
|
198
|
+
(skillName) =>
|
|
199
|
+
typeof skillName !== "string" ||
|
|
200
|
+
!/^[a-z0-9-]{1,63}$/.test(skillName),
|
|
201
|
+
)
|
|
202
|
+
) {
|
|
203
|
+
throw new Error("invalid ownership manifest");
|
|
204
|
+
}
|
|
205
|
+
return manifest;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
if (error?.code !== "ENOENT") {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`Unable to read ${path.join(destination, manifestName)}: ${error.message}`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
package: packageJson.name,
|
|
214
|
+
version: packageJson.version,
|
|
215
|
+
skills: [],
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async function writeInstallManifest(destination, manifest, dryRun) {
|
|
221
|
+
if (dryRun) return;
|
|
222
|
+
await writeFile(
|
|
223
|
+
path.join(destination, manifestName),
|
|
224
|
+
`${JSON.stringify(manifest, null, 2)}\n`,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async function installInto(destination, skillNames, options, agent) {
|
|
229
|
+
const previous = await readInstallManifest(destination);
|
|
230
|
+
const existing = [];
|
|
231
|
+
for (const skillName of skillNames) {
|
|
232
|
+
if (await pathExists(path.join(destination, skillName))) existing.push(skillName);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (existing.length > 0 && !options.force) {
|
|
236
|
+
throw new Error(
|
|
237
|
+
`Existing skills at ${destination}: ${existing.join(", ")}. Re-run with --force to replace them.`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
console.log(`${options.dryRun ? "Would install" : "Installing"} ${skillNames.length} skills to ${destination}`);
|
|
242
|
+
if (!options.dryRun) await mkdir(destination, { recursive: true });
|
|
243
|
+
|
|
244
|
+
for (const skillName of skillNames) {
|
|
245
|
+
const source = path.join(skillsSource, skillName);
|
|
246
|
+
const target = path.join(destination, skillName);
|
|
247
|
+
const staging = path.join(destination, `.${skillName}.tmp-${process.pid}`);
|
|
248
|
+
const backup = path.join(destination, `.${skillName}.bak-${process.pid}`);
|
|
249
|
+
console.log(`- ${skillName}`);
|
|
250
|
+
if (options.dryRun) continue;
|
|
251
|
+
|
|
252
|
+
await rm(staging, { recursive: true, force: true });
|
|
253
|
+
await cp(source, staging, { recursive: true });
|
|
254
|
+
if (await pathExists(target)) {
|
|
255
|
+
await rename(target, backup);
|
|
256
|
+
try {
|
|
257
|
+
await rename(staging, target);
|
|
258
|
+
await rm(backup, { recursive: true, force: true });
|
|
259
|
+
} catch (error) {
|
|
260
|
+
await rename(backup, target);
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
} else {
|
|
264
|
+
await rename(staging, target);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const currentSkills = new Set(skillNames);
|
|
269
|
+
for (const previousSkill of previous.skills ?? []) {
|
|
270
|
+
if (!currentSkills.has(previousSkill) && !options.dryRun) {
|
|
271
|
+
await rm(path.join(destination, previousSkill), { recursive: true, force: true });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
await writeInstallManifest(destination, {
|
|
276
|
+
package: packageJson.name,
|
|
277
|
+
version: packageJson.version,
|
|
278
|
+
agent,
|
|
279
|
+
installedAt: new Date().toISOString(),
|
|
280
|
+
completePack: true,
|
|
281
|
+
skills: [...currentSkills].sort(),
|
|
282
|
+
}, options.dryRun);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function uninstallFrom(destination, options) {
|
|
286
|
+
const manifest = await readInstallManifest(destination);
|
|
287
|
+
const tracked = new Set(manifest.skills ?? []);
|
|
288
|
+
if (tracked.size === 0) {
|
|
289
|
+
throw new Error(`No ${packageJson.name} installation manifest found at ${destination}.`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const skillNames = [...tracked];
|
|
293
|
+
|
|
294
|
+
console.log(`${options.dryRun ? "Would remove" : "Removing"} ${skillNames.length} skills from ${destination}`);
|
|
295
|
+
for (const skillName of skillNames) {
|
|
296
|
+
console.log(`- ${skillName}`);
|
|
297
|
+
if (!options.dryRun) {
|
|
298
|
+
await rm(path.join(destination, skillName), { recursive: true, force: true });
|
|
299
|
+
tracked.delete(skillName);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (!options.dryRun) {
|
|
304
|
+
await rm(path.join(destination, manifestName), { force: true });
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
async function main() {
|
|
309
|
+
const options = parseArgs(process.argv.slice(2));
|
|
310
|
+
if (options.command === "help") {
|
|
311
|
+
printHelp();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (options.command === "version") {
|
|
315
|
+
console.log(packageJson.version);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const allSkills = await availableSkills();
|
|
320
|
+
if (options.command === "list") {
|
|
321
|
+
console.log("Agent targets:");
|
|
322
|
+
for (const [name, target] of Object.entries(targets)) {
|
|
323
|
+
console.log(`- ${name}: ${target.label}`);
|
|
324
|
+
}
|
|
325
|
+
console.log("- custom: any skills directory supplied with --path");
|
|
326
|
+
console.log("\nPack skills:");
|
|
327
|
+
for (const skillName of allSkills) console.log(`- ${skillName}`);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (!["install", "uninstall"].includes(options.command)) {
|
|
332
|
+
throw new Error(`Unknown command: ${options.command}`);
|
|
333
|
+
}
|
|
334
|
+
if (options.agents.length === 0) {
|
|
335
|
+
throw new Error("Specify at least one --agent target.");
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const destinations = new Map();
|
|
339
|
+
for (const requestedAgent of options.agents) {
|
|
340
|
+
const agent = normalizeAgent(requestedAgent);
|
|
341
|
+
const destination = resolveDestination(agent, options);
|
|
342
|
+
if (!destinations.has(destination)) destinations.set(destination, agent);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
for (const [destination, agent] of destinations) {
|
|
346
|
+
if (options.command === "install") {
|
|
347
|
+
await installInto(destination, allSkills, options, agent);
|
|
348
|
+
} else {
|
|
349
|
+
await uninstallFrom(destination, options);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
main().catch((error) => {
|
|
355
|
+
console.error(`Error: ${error.message}`);
|
|
356
|
+
process.exitCode = 1;
|
|
357
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "threejs-awesome-graphics-agent-skills",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Expert agent skills for creating exceptional Three.js graphics.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Scott",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"agent-skills",
|
|
9
|
+
"threejs",
|
|
10
|
+
"three.js",
|
|
11
|
+
"codex",
|
|
12
|
+
"claude-code",
|
|
13
|
+
"cursor",
|
|
14
|
+
"copilot",
|
|
15
|
+
"gemini-cli",
|
|
16
|
+
"windsurf",
|
|
17
|
+
"procedural-graphics",
|
|
18
|
+
"webgpu",
|
|
19
|
+
"tsl",
|
|
20
|
+
"glsl",
|
|
21
|
+
"shaders",
|
|
22
|
+
"volumetric-rendering",
|
|
23
|
+
"post-processing"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"bin": {
|
|
27
|
+
"threejs-awesome-graphics-agent-skills": "bin/threejs-awesome-graphics-agent-skills.mjs"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
".codex-plugin/",
|
|
31
|
+
"bin/",
|
|
32
|
+
"skills/",
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"validate": "node scripts/validate-pack.mjs",
|
|
44
|
+
"test": "npm run validate && npm run test:routing && npm run test:references && npm run test:installer && npm run test:gallery",
|
|
45
|
+
"dev:examples": "node dev/example-gallery/server.mjs --open",
|
|
46
|
+
"dev:examples:no-open": "node dev/example-gallery/server.mjs",
|
|
47
|
+
"dev:examples:fixture": "node dev/example-gallery/server.mjs --open --include-fixtures",
|
|
48
|
+
"capture:examples": "node scripts/capture-examples.mjs",
|
|
49
|
+
"test:references": "node scripts/test-reference-examples.mjs",
|
|
50
|
+
"test:routing": "node scripts/test-agent-routing.mjs",
|
|
51
|
+
"test:installer": "node scripts/test-installer.mjs",
|
|
52
|
+
"test:gallery": "node scripts/test-example-gallery.mjs",
|
|
53
|
+
"check:freshness": "node scripts/check-three-freshness.mjs",
|
|
54
|
+
"test:all": "npm test && npm run check:freshness",
|
|
55
|
+
"prepack": "npm run test:all",
|
|
56
|
+
"prepublishOnly": "npm run check:freshness"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"playwright": "^1.60.0",
|
|
60
|
+
"three": "^0.184.0",
|
|
61
|
+
"yaml": "^2.9.0"
|
|
62
|
+
}
|
|
63
|
+
}
|