Modern GLSL Shader Development in Zed & VS Code: Zero Setup, Real-Time Diagnostics A developer built an open-source, Rust-based GLSL language server that provides zero-setup shader development in both Zed and VS Code, using AI assistance during development. The tool validates shaders against the glslang compiler backend in real time, offering instant diagnostics, autocompletion, signature help, go-to-definition, and background #include resolution for shared GLSL headers. It supports per-file targeting of Desktop OpenGL and Vulkan SPIR-V via a // @target: vulkan directive. Writing GLSL shaders often feels like stepping ten years back in time compared to modern web or backend development. Whether you are targeting modern Desktop OpenGL or Vulkan, finding an editor setup that just works out of the box is surprisingly difficult. Recently, while trying to get a decent shader workflow running across Zed and VS Code , I kept hitting the same roadblocks: version 330 to 460 core or Vulkan SPIR-V, they start throwing false, confusing errors. include resolution: Instead of constantly fighting with fragmented tools, I decided to build a unified solution with the help of AI: a lightweight Rust-based language server supporting both Zed and VS Code with zero manual setup. The project is completely open source. If you want to jump straight into the code or install it for your editor, you can find the repository here: .xyzw , .rgba , functions, and structs. glslang in the background. To see how this works, let's create a basic vertex shader inside a glsl/ directory named standart.vert : version 460 core layout location = 0 in vec3 aPos; void main { gl Position = vec4 aPos, 1.0 ; } Now, let's say we accidentally omit the semicolon on the gl Position assignment: void main { gl Position = vec4 aPos, 1.0 // Missing semicolon } The moment you stop typing, the language server validates the shader against the compiler backend and immediately highlights the syntax error with precise line and column information: No need to recompile your engine or run command-line tools—you catch typos the second you make them. In real-world projects, shaders share math helpers, camera matrices, and lighting calculations. To keep things modular, let's create a shared header named common.glsl : mat4 calculateMVP mat4 modelMatrix, mat4 viewMatrix, mat4 projectionMatrix { return projectionMatrix viewMatrix modelMatrix; } vec3 TransformToWorldSpace mat4 modelMatrix, vec3 position { return vec3 modelMatrix vec4 position, 1.0 ; } vec4 TransformToClipSpace mat4 modelMatrix, mat4 viewMatrix, mat4 projectionMatrix, vec4 position { return projectionMatrix viewMatrix modelMatrix position; } vec3 TransformNormalToWorldSpace mat3 normalMatrix, vec3 normal { return normalize normalMatrix normal ; } vec3 TransformNormalToWorldSpace mat4 normalMatrix, vec3 normal { return normalize mat3 normalMatrix normal ; } We assume normal matrix inversion/transposition is pre-calculated on the CPU side . Standard GLSL does not support include without compiler extensions. By enabling GL ARB shading language include or GL GOOGLE include directive , we can cleanly include our shared header inside standart.vert : version 460 core extension GL ARB shading language include : enable include "common.glsl" layout location = 0 in vec3 aPos; out vec3 FragPos; layout location = 0 in vec3 aNormal; out vec3 Normal; layout location = 0 in vec2 aTexCoords; out vec2 TexCoords; uniform mat4 model, normal; uniform mat4 view, projection; void main { TexCoords = aTexCoords; FragPos = TransformToWorldSpace model, aPos ; Normal = TransformNormalToWorldSpace normal, aNormal ; gl Position = TransformToClipSpace model, view, projection, vec4 aPos, 1.0 ; } The language server immediately parses common.glsl in the background. You get instant autocompletion for all helper functions: Along with full signature help and parameter hints while typing function arguments: You can also press F12 Go to Definition on functions like TransformToClipSpace to jump straight to their definition in common.glsl . If your engine targets Vulkan, your shader requirements are different: you use descriptor sets set = X, binding = Y , push constants, and compile directly to SPIR-V. You can tell the language server to validate specifically for Vulkan on a per-file basis using the // @target: vulkan directive at the top of your shader: // @target: vulkan version 460 layout location = 0 in vec3 inPosition; layout location = 1 in vec3 inNormal; layout location = 2 in vec2 inTexCoord; layout set = 0, binding = 0 uniform CameraBuffer { mat4 view; mat4 projection; } camera; layout push constant uniform PushConstants { mat4 model; } pc; layout location = 0 out vec3 outFragPos; layout location = 1 out vec3 outNormal; layout location = 2 out vec2 outTexCoord; void main { outFragPos = vec3 pc.model vec4 inPosition, 1.0 ; outNormal = mat3 pc.model inNormal; outTexCoord = inTexCoord; gl Position = camera.projection camera.view vec4 outFragPos, 1.0 ; } With // @target: vulkan , the language server automatically switches the compiler backend to strict SPIR-V validation mode. It properly checks descriptor sets, push constant alignment, and Vulkan-specific qualifiers without complaining about missing OpenGL uniforms: You do not even need to write per-file directives. You can configure the target API globally or per-workspace in your settings.json : { "lsp": { "glsl validator": { "initialization options": { "target api": "vulkan" } } } } You can always override this per-file using // @target: vulkan or // @target: opengl at the top of any shader . Getting a fast, zero-configuration GLSL environment working across Zed and VS Code solved a huge daily pain point in my graphics workflow. Next up, I built the exact same zero-bloat workflow for HLSL and Unity ShaderLab , powered by Microsoft's DirectX Shader Compiler dxc . I will be sharing a breakdown of that setup in a follow-up post. If you want to try it out, you can find the project, installation guides, and full documentation on GitHub: 👉 glsl-extended on GitHub https://github.com/zyr1on/glsl-extended Feel free to open an issue if you encounter edge cases or have feature requests. What does your current shader development workflow look like? Which editor do you rely on most for writing shaders? Let me know in the comments