ソース情報
- リポジトリ
- cwilliams5/Alt-Tabby
- ソースの最終更新活動
- 2026年3月7日 05:24
- 検出された SKILL.md の言語
- 英語
- スター
- 4
- フォーク
- 0
インストール方法
デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。
ソースファイルを確認
インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。
メニュー
デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。
インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/cwilliams5/Alt-Tabby --skill shader-convertコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?SkillsMP が現在取得できるファイルをダウンロードできます。
Audit all lint-ignore suppressions for appropriateness and overuse
Pre-flight checklist — run high-signal review skills before a release
Discover functions that block the main thread, then micro-audit each for internal optimization opportunities
SOC 職業分類に基づく
SKILL.md を表示中
| name | shader-convert |
| description | Convert Shadertoy GLSL shaders to HLSL for Alt-Tabby's D3D11 pipeline |
| user-invocable | true |
| disable-model-invocation | true |
Convert Shadertoy GLSL shaders to the Alt-Tabby HLSL pixel shader format.
/shader-convert — Scan src/shaders/ (and subdirs mouse/, selection/) for any .glsl without matching .hlsl, convert all/shader-convert <Shadertoy URL> — Fetch shader from Shadertoy via Playwright, then convert/shader-convert <pasted GLSL + metadata> — Convert manually pasted shader sourceNot supported: Multi-buffer shaders (Buffer A/B/C/D tabs). Our pipeline is single-pass only. Skip shaders that require inter-frame feedback or multi-pass rendering.
src/shaders/ and subdirs src/shaders/mouse/, src/shaders/selection/ for any name.glsl that has no matching name.hlsl.hlsl (and .json if missing)src/shaders/mouse/, selection shaders in src/shaders/selection/, background shaders in src/shaders/shadertoy.com/view/)Requires the Playwright MCP server. Extracts shader source, metadata, and iChannel textures automatically.
The Playwright MCP is not loaded by default — it's toggled on-demand to avoid context bloat.
Check if you have access to mcp__playwright__browser_navigate. If NOT available:
powershell -File tools/toggle-playwright-mcp.ps1 on
browser_navigate → https://www.shadertoy.com/view/{id}
If Cloudflare challenge appears, wait ~10s for auto-pass. Verify the page title changes from "Shader - Shadertoy BETA" to the shader name.
() => {
const st = window.gShaderToy;
if (!st) return { error: 'gShaderToy not found' };
// Metadata
const info = st.mInfo;
// Code from each pass via CodeMirror Doc
const passes = st.mPass.map((p, i) => {
const code = p.mDocs && typeof p.mDocs.getValue === 'function'
? p.mDocs.getValue() : null;
return { index: i, code, charCount: code ? code.length : 0 };
});
// Tab names → map pass index to role
const tabNames = {};
for (let i = 0; i < 10; i++) {
const tab = document.getElementById('tab' + i);
if (tab) tabNames['tab' + i] = tab.textContent.trim();
}
// Pass types from effect renderer (image, common, buffer, sound, cubemap)
const passTypes = st.mEffect ? st.mEffect.mPasses.map( ({
: i, : p.
})) : [];
iChannels = [];
(st. && st..) {
imgPass = st...( p. === ) || st..[];
(imgPass && imgPass.) {
iChannels = imgPass..( {
(!inp) ;
.(.(inp.));
});
}
}
{
: { : info., : info., : info., : info. },
passes, tabNames, passTypes, iChannels
};
}
Check passTypes — if any pass has type of "buffer", "sound", or "cubemap":
"buffer" → STOP: Multi-buffer shader, not supported. Tell user."sound" → STOP: Audio-output shader, not supported."cubemap" → STOP: Cubemap pass, not supported."image" and "common" are valid.Check iChannels for audio inputs:
mType !== "texture" (e.g., "music", "musicstream", "webcam", "video", "keyboard"), note it. Audio channels will need synthetic beat replacement (see §7). Webcam/video/keyboard → skip the shader.Combine passes into a single .glsl file:
"common" tab exists: put Common code first, then // --- Image --- separator, then Image codename from info.name → snake_case (e.g., "Power (Chainsaw Man)" → power_chain_saw_man)For each non-null iChannel with mType === "texture":
// In browser_run_code (needs Playwright page object for download API)
// NOTE: page.evaluate only accepts one arg — wrap multiple values in an object
async (page) => {
const textures = [
{ url: 'https://www.shadertoy.com' + mSrc0, file: 'name_i0.png' },
{ url: 'https://www.shadertoy.com' + mSrc1, file: 'name_i1.png' }
];
const results = [];
for (const tex of textures) {
const downloadPromise = page.waitForEvent('download', { timeout: 15000 });
await page.evaluate(({url, filename}) => {
return fetch(url).then(r => r.blob()).then(blob => {
const blobUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = blobUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
..(a);
.(blobUrl);
});
}, {: tex., : tex.});
download = downloadPromise;
download.( + tex.);
results.(tex.);
}
results;
}
https://www.shadertoy.com + mInfo.mSrc (e.g., /media/a/...png)src/shaders/{name}_i{channel}.pngPopulate from extracted info:
name → info.nameshadertoyId → the ID from the URLauthor → info.usernamelicense → "CC BY-NC-SA 3.0" (Shadertoy default)iChannels → from downloaded textures, include filter/wrap from mSamplerClose the browser (browser_close) immediately — before writing any files or starting HLSL conversion. The Playwright MCP server is a shared resource; holding it open blocks other agents. Extract all data into local variables in Steps 2-5, then close the browser as the very first action in this step.
Proceed to HLSL conversion (same as Mode C).
After Mode B is fully complete (conversion, bundle, compile, tests), remind the user:
"Playwright MCP is still enabled and consuming context. To disable it for future sessions, run:"
powershell -File tools/toggle-playwright-mcp.ps1 off
src/shaders/name.glsl with the pasted sourcesrc/shaders/name.json with metadata (prompt for Shadertoy URL/author if not provided)src/shaders/name.hlsl| GLSL | HLSL |
|---|---|
vec2, vec3, vec4 | float2, float3, float4 |
ivec2, ivec3, ivec4 | int2, int3, int4 |
mat2, mat3, mat4 | float2x2, float3x3, float4x4 |
fract() | frac() |
mod(a, b) | fmod(a, b) |
mix(a, b, t) | lerp(a, b, t) |
texture(sampler, uv) | tex.Sample(samplerState, uv) |
texelFetch(sampler, coord, lod) | tex.Load(int3(coord, lod)) |
atan(y, x) | atan2(y, x) |
dFdx(), dFdy() | ddx(), ddy() |
GLSL allows vec3(x) as shorthand for vec3(x, x, x). HLSL does too with float3(x, x, x) or (float3)x.
| Shadertoy | HLSL cbuffer |
|---|---|
iTime | time |
iResolution.xy | resolution |
iResolution (vec3) | float3(resolution, 1.0) |
iTimeDelta | timeDelta |
iFrame | frame |
fragCoord | input.pos.xy (from SV_Position) |
fragColor | return value of PSMain |
Replace void mainImage(out vec4 fragColor, in vec2 fragCoord) with:
// PSInput and cbuffer are provided by alt_tabby_common.hlsl (prepended automatically)
float4 PSMain(PSInput input) : SV_Target {
float2 fragCoord = input.pos.xy;
// ... converted body ...
return AT_PostProcess(color); // instead of manual post-processing
}
Y-axis flip: Shadertoy's fragCoord.y = 0 is at the bottom of the screen; SV_Position.y = 0 is at the top. For shaders with gravity, falling particles, directional motion, or any up/down asymmetry, flip Y at the start:
float2 fragCoord = float2(input.pos.x, resolution.y - input.pos.y);
Symmetric shaders (noise fields, clouds, fractals) usually don't need the flip.
The cbuffer and PSInput struct are provided by alt_tabby_common.hlsl, which is prepended automatically before compilation. Do NOT include them in the .hlsl file. The common header provides:
cbuffer Constants : register(b0) with all uniforms (144 bytes, 9 × 16-byte rows):
time (float), resolution (float2), timeDelta (float), frame (uint), darken (float), desaturate (float), opacity (float)iMouse (float2, cursor px), iMouseVel (float2, velocity px/sec), iMouseSpeed (float, magnitude of velocity)gridW (uint, grid width, 0 = no grid), gridH (uint, grid height, 0 = no grid), maxParticles (uint, particle slots excluding grid cells), reactivity (float, cursor force multiplier)selRect (float4, x/y/w/h), selColor (float4, premul RGBA), borderColor (float4, premul RGBA), borderWidth (float), isHovered (float, intensity: 1.0 = full selected, <1.0 = dimmed for hover), entranceT (float), selGlow (float, outer glow radius multiplier), selIntensity (float, effect blend strength), rowRadius (float, user's RowRadius in pixels, 0 = shader decides)struct PSInput with SV_Position and TEXCOORD0AT_PostProcess(float3 col) and AT_PostProcess(float3 col, float customAlpha) functionsAll fields are populated every frame for all shader categories. Background shaders typically use only core fields. Mouse shaders use core + mouse fields. Selection shaders use core + selection fields.
Compute-enabled mouse shaders access the same cbuffer via register(b0) in both CSMain and PSMain. The common header is prepended for both entry points during compilation.
iChannel Texture2D/SamplerState declarations still go in the individual .hlsl file (they vary per shader and are NOT in the common header).
Standard shaders (alpha from brightness): End PSMain with return AT_PostProcess(color);
Shaders with custom alpha (transparency masks, particle alpha, etc.): End PSMain with return AT_PostProcess(color, customAlpha);
AT_PostProcess handles darken, desaturate, opacity multiplication, and premultiplied alpha output. Do NOT write these manually.
Shadertoy shaders may use iChannel0..3 for audio input (spectrum/waveform) or produce audio output via a "Sound" tab.
Audio input (e.g., texture(iChannel0, vec2(freq, 0.0)).r for spectrum): Replace with a gentle time-based pulse so the shader retains dynamic variation without requiring audio hardware:
float getBeat() {
return smoothstep(0.6, 0.9, pow(sin(time * 1.5) * 0.5 + 0.5, 4.0)) * 0.3;
}
Adjust frequency/amplitude to match how the original used the audio data (subtle background pulse vs heavy bass reactivity).
Audio output ("Sound" tab shaders): Remove entirely. Alt-Tabby is visual only.
Shadertoy provides iMouse (pixel coordinates, click state). Alt-Tabby provides mouse data via cbuffer:
iMouse (float2): cursor position in physical pixelsiMouseVel (float2): cursor velocity in pixels/second (smoothed, CPU-computed)iMouseSpeed (float): magnitude of iMouseVel (convenience scalar)For background shaders (no mouse interaction): Zero out or ignore iMouse. Set any derived mouse variables to (float2)0 and simplify away dead code. If mouse is the sole camera control, replace with a time-based sweep:
float2 fakeMouse = float2(
sin(time * 0.1) * 0.3,
cos(time * 0.07) * 0.2
);
For mouse-category shaders: Use iMouse for cursor position, iMouseVel for direction-dependent effects (particles trailing behind cursor), and iMouseSpeed for motion gating (e.g., if (iMouseSpeed < threshold) return zero). Speed-gated effects should use smoothstep() for gradual activation rather than hard cutoffs.
If the shader uses iChannel0..3:
src/shaders/name_i0.png, name_i1.png, etc..json metadata:
"iChannels": [{"index": 0, "file": "name_i0.png", "filter": "linear", "wrap": "repeat"}]
Texture2D iChannel0 : register(t0);
SamplerState samp0 : register(s0);
texture(iChannelN, uv) with iChannelN.Sample(sampN, uv)Run the bundle script:
powershell -File tools/shader_bundle.ps1
Compile shaders to DXBC:
powershell -File tools/shader_compile.ps1
Run tests:
.\tests\test.ps1
{
"name": "Display Name",
"shadertoyId": "XXXXXX",
"author": "Author Name",
"license": "CC BY-NC-SA 3.0",
"opacity": 0.50,
"iChannels": [],
"timeOffsetMin": 40,
"timeOffsetMax": 120,
"timeAccumulate": true
}
opacity: Default layer opacity when compositing (0.0-1.0)iChannels: Array of texture references (empty if no textures needed)timeOffsetMin: (optional) Minimum random time offset in seconds. Skips the shader's warmup period so it looks interesting immediately. Falls back to config ShaderTimeOffsetMin (default 30) if omitted.timeOffsetMax: (optional) Maximum random time offset in seconds. Falls back to config ShaderTimeOffsetMax (default 90) if omitted. Set higher for shaders with long warmup (e.g., volumetric fog needs 40-120s).timeAccumulate: (optional) When true, shader time persists across overlay show/hide so it picks up where it left off. Falls back to config ShaderTimeAccumulate (default true) if omitted. Set false for shaders with a deliberate intro animation you want to see each time.category: (optional) "mouse" or "selection" for shaders in subdirectories. Background shaders (root dir) omit this field.compute: (optional) { "maxParticles": N, "particleStride": 32, "baseParticles": M }. When present, the shader is compiled as a compute+pixel pair. CS entry point is CSMain (compiled with cs_5_0), PS entry point is PSMain (compiled with ps_5_0), both in the same .hlsl file. The compute shader writes to RWStructuredBuffer via UAV; the pixel shader reads the same buffer as StructuredBuffer at register(t4). Only used for mouse-category shaders that need persistent GPU-side state (particles, waves).
baseParticles is the shader's intrinsic particle count (0 for pure-grid fluids, 128/384 for particle+grid). maxParticles in the JSON is the default total (= baseParticles + gridW * gridH at high quality). At runtime, actual buffer size is computed from baseParticles * ParticleDensity + gridW * gridH where grid dimensions come from GridQuality config.Add time fields when the shader has a notable warmup period or deliberate intro. Omit them for shaders that look good immediately at any time value.
Note on shader models: Compute shaders require cs_5_0 profile (DX11 feature level 11_0). Compute-paired pixel shaders use ps_5_0. Background and selection shaders remain ps_4_0 for maximum compatibility.
Compute-enabled mouse shaders follow one of three buffer layout patterns:
[particles 0..N-1] [grid cells N..N+W*H-1]. CS particle threads do physics, CS grid threads accumulate nearby particles. PS bilinear-samples the grid. Grid cells reuse the Particle struct: pos.xy = accumulated RG, vel.xy = accumulated BA.[grid cells 0..W*H-1]. CS runs wave/fluid equations. PS samples the grid.[slots 0..N-1]. CS manages slot lifecycle. PS loops over all slots.Shaders are organized into three categories by directory:
src/shaders/): Composited as stackable layers behind the window list. Up to 4 layers.src/shaders/mouse/): Single-slot effect receiving cursor data: iMouse (position), iMouseVel (velocity px/sec), iMouseSpeed (speed magnitude). Add "category": "mouse" to JSON.src/shaders/selection/): Single-slot effect for row selection highlight. Receives selRect, selColor, borderColor, borderWidth, isHovered, entranceT, selGlow, selIntensity, rowRadius via cbuffer. isHovered is an intensity multiplier (1.0 = full selected, <1.0 = dimmed for hover reuse) — use it directly as float intensity = isHovered;. Do NOT hardcode hover dimming (e.g., lerp(1.0, 0.45, isHovered) is wrong). For corner radius, use rowRadius > 0.0 ? rowRadius : min(hs.x, hs.y) * 0.15 so the shader respects the user's RowRadius setting while falling back to 15% of the smaller half-dimension. Add "category": "selection" to JSON.