Build1 publisher2 min readPublished
A shader language server fetches glslang so the editor's errors match a real compiler
A developer hit no diagnostics in Zed and WebGL-era false errors in VS Code, then wrote a Rust language server that hands each shader to glslang. The diagnostics inherit whatever glslang build it fetches.
The Engineer · Build desk
What happened
- A developer working across Zed and VS Code reported that Zed gave no real-time feedback on syntax or type errors with a shader file open, and no compiler diagnostics at all.
- In VS Code, the post says most popular GLSL extensions were built years ago for WebGL and throw false errors once a file declares #version 330 to 460 core or targets Vulkan SPIR-V.
- Engines typically run #include through their own C++ preprocessors, and editor extensions cannot follow those headers, so autocomplete and navigation break across shared files.
- The author's answer is an open source Rust language server for both editors, built with AI help, offering real-time diagnostics for Desktop OpenGL and Vulkan SPIR-V with no manual setup.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- capability A team can keep camera matrices and lighting helpers in one shared header and still get definitions and signature help in the editor, so modularising shaders no longer costs navigation.
- constraint The diagnostics are only as accurate as the glslang build the extension pulled down, so a shader your engine compiles can still light up red, and the false-error problem returns in a new place.
- decision Shops that forbid tools from downloading executables now choose between the zero-setup promise and vendoring a glslang they control.
Stop typing, and the server hands the shader to a compiler backend; the error comes back with line and column [12]. The backend is glslang, and the extension downloads and manages the binary itself [11]. The red underline in your editor is glslang's reading of that file.
Standard GLSL has no `#include`, so the sample vertex shader turns on `GL_ARB_shading_language_include`, and the post names `GL_GOOGLE_include_directive` as the other route [13]. Engine-side preprocessors written in C++ do their own stitching [6]. glslang sees the same translation unit only if the search paths and the defines line up. Where they diverge, valid shaders show errors again. False errors on modern GLSL were the original complaint [4].
On the editor side, the server parses the header in the background and resolves symbols, functions and structs recursively [9], with F12 on `TransformToClipSpace` jumping into `common.glsl` [15]. Autocomplete is context aware for vector swizzles, `.xyzw` and `.rgba` [10]. The shared header in the example carries two overloads of `TransformNormalToWorldSpace`, one taking a mat3 and one taking a mat4 [16].
The sample listing declares `aPos`, `aNormal` and `aTexCoords`, each with `layout(location = 0)` [14]. The walkthrough demonstrates the missing semicolon after `gl_Position = vec4(aPos, 1.0)` [17]. A duplicated input location is what I would test a compiler-backed checker on first, since a keyword-list linter has no way to see it.
This is one developer's account of their own two editors. The post does not disclose the extensions it faults or the glslang version the server fetches [18]. The developer wrote that opening a shader in Zed "felt like using basic Notepad with some colors" [3], and reported no real-time feedback for syntax or type errors there [2]. Several of the VS Code extensions tried either failed to load or lacked basic keyword definitions [5].
The adoption cost sits in that background download [11]. An extension that fetches and runs a compiler executable the first time you open a file is a review item on a managed workstation, and whatever version arrives is the version your diagnostics inherit. If you ship against a particular glslang, zero manual setup [7] is working against you. The project is open source, so the fetch path is readable before you install it [7].
What to watch
- A named extension-and-version comparison would turn one developer's account into something another team can reproduce.
- Configuration for engine-side defines and include search paths appearing in the repository, so the diagnostics can follow a real build.