modkit bgfx shaders
First-class editor support for bgfx/modkit
shaders in VS Code: syntax highlighting, snippets, IntelliSense, and inline
shaderc diagnostics for .sc, .def.sc, and bgfx .sh include files.
Features
- Syntax highlighting
.sc — vertex / fragment / compute shaders ($input/$output, SAMPLER2D(...), GLSL types, bgfx & modkit functions, gl_* / u_* built-ins, the C preprocessor).
.def.sc — varying / attribute definitions with their : SEMANTIC bindings and defaults.
- bgfx
.sh — shader includes (header guards, #define, mk* helpers).
- Snippets — vertex/fragment/compute skeletons,
SAMPLER2D, uniform, include guards, and varying templates.
- Hover & completion — documentation for bgfx built-ins (
mul, texture2DLod, SAMPLER2D, u_modelViewProj, …), modkit helpers scraped from shaders/include/*.sh, and every symbol reachable through the file's own #include graph.
- Navigation — go-to-definition for
#include "…" targets and for symbols: F12 on mkSlugRender opens shaders/include/mk_slug.sh. Plus a document-symbol outline.
- Diagnostics — compile the current shader with your local
shaderc and see errors inline (lint on open and on save, a command, and a shaderc task with a $shaderc problem matcher).
- Pre-compile checks — an unresolvable
#include is flagged on its own line, and $input/$output names are cross-checked against the resolved varying.def.sc, before shaderc ever runs.
- Project detection — finds the modkit SDK whether you are in the modkit checkout, a project that vendors it at
deps/modkit, or one that uses an installed SDK. The status bar shows which root and which config source is in play.
The .sh problem (and how this handles it)
bgfx uses .sh for shader headers, but .sh normally means shell script. To
avoid hijacking real shell scripts, this extension does not claim .sh
globally. Instead it uses two complementary mechanisms:
- Content detection — a
.sh file whose first non-blank line looks like a
shader header (#ifndef, #include, #define, $input, …) is treated as a
bgfx shader. Shell scripts start with #!/bin/sh, which is deliberately not matched.
- Scoped association — a default
files.associations maps .sh under
**/shaders/**, **/shaders/include/**, and **/deps/bgfx/** to the shader
language. Shell scripts elsewhere stay shell.
You can always override per workspace:
// .vscode/settings.json
"files.associations": { "**/my/shaders/**/*.sh": "bgfx-shader" }
Note on .sc: the .sc extension is also used by Scala (Metals) and
SuperCollider. Inside a modkit workspace this extension's association wins; if
you mix ecosystems, pin the language with files.associations.
Where the compile settings come from
A shader's varying def, include dirs and defines are project data, not something a
filename can tell you: fs_bloom_down.sc uses varying_fullscreen.def.sc and
fs_particle.sc uses varying_particle_render.def.sc, and that mapping lives in
CMakeLists.txt. So the extension resolves each shader in three tiers, highest first:
- Your settings — an explicit
modkit.shaderc.varyingDef, extra includeDirs, defines.
- The build tree — the real
shaderc command line for that file, read out of the
generated build.ninja / build.make. Exact, and free. Entries are matched to the
platform and profile being validated, so a web build's defines never leak into a
desktop check. The recorded profile itself is never replayed (see the note below).
- Heuristics — the layout on disk, when the shader has no build entry (for example
when it sits behind a disabled CMake option).
The status bar shows which tier won; hover it for the full resolved setup.
A note on modkit.shaderc.profile: bgfx passes GLSL 4xx profiles straight through
without compiling them, so --profile 440 exits 0 and writes output even for a syntax
error. Only spirv (glslang) and 120 / 300_es actually validate. Leave this at
spirv unless you know why you are changing it.
Settings
| Setting |
Default |
Description |
modkit.root |
auto |
Path to the modkit SDK. auto searches upwards for shaders/include/mk_common.sh. |
modkit.shaderc.path |
"" |
Path to shaderc. Empty = the detected root's tools/bin/shaderc, then PATH. |
modkit.shaderc.platform |
auto |
--platform (auto-detected from the host OS). |
modkit.shaderc.profile |
spirv |
--profile used for validation. |
modkit.shaderc.includeDirs |
[] |
Extra -i dirs, appended to the derived ones. |
modkit.shaderc.defines |
[] |
Extra --define values, appended to any read from the build tree. |
modkit.shaderc.varyingDef |
auto |
auto uses the build tree, then derives varying_<name>.def.sc. |
modkit.shaderc.useBuildDir |
true |
Read compile settings from the generated build files. |
modkit.shaderc.buildDir |
auto |
Build directory to read them from. |
modkit.lint.enable |
true |
Surface shaderc errors as diagnostics. |
modkit.lint.onSave |
true |
Re-run on save. |
modkit.lint.onOpen |
true |
Check a shader when it is opened. |
Commands
- modkit: Compile Current Shader (shaderc) — validates the active
.sc and reports success/errors.
- modkit: Check Current Shader for Errors — silent validation; publishes diagnostics only.
Maintaining the built-in docs
Hover/completion data lives in data/builtins.json. Regenerate it from a modkit
checkout:
npm run gen:builtins -- /path/to/modkit/shaders/include
Development
npm install
npm run build # bundle to dist/extension.js
npm test # type-check and run local unit tests
npm run watch # incremental rebuilds
npm run package # produce a .vsix (vsce)
# Replay resolution over every shader in a project and report what the Problems
# panel would show. A failure here is a red squiggle on correct code.
node tools/lint-sweep.mjs ../modkit --verbose
node tools/lint-sweep.mjs --explain ../modkit/shaders/fs_pbr_core.sc
Press F5 in VS Code to launch an Extension Development Host.
License
MIT — see LICENSE.
| |