VPFX Pack Author Quick Start
This document is for shaderpack authors who want to create external VPFX packs.
The goal is simple:
Create a minimal VPFX pack.Load it in-game.Modify the final fragment shader.Reload it quickly.Confirm that the pack works.This guide does not require modifying VPFX Java code. You only need to create files inside a VPFX shaderpack zip.
1. What you are building
A VPFX pack is an external shaderpack written specifically for VPFX.
A minimal VPFX pack can:
Read the current scene color.Run a fullscreen post-processing shader.Write the result back to the main screen.In other words:
minecraft:scene_color | vyour fragment shader | vminecraft:mainFor your first pack, do not start with shadows, depth reconstruction, bloom chains, or multiple render targets. Start with one simple pass.
2. What VPFX packs are not
VPFX packs are not OptiFine shaderpacks.
VPFX packs are not Iris shaderpacks.
You should not expect an existing OptiFine or Iris shaderpack to run in VPFX without being rewritten.
A VPFX pack has its own structure:
pack.jsonpost_effect/shaders/A VPFX pack should be written specifically for the VPFX runtime.
3. Requirements
You need:
Minecraft with VPFX installedA text editorBasic GLSL knowledgeA zip toolAccess to the .minecraft/shaderpacks/ folderRecommended editor:
Visual Studio CodeIntelliJ IDEAAny editor with JSON and GLSL highlightingYou do not need:
Java modding knowledgeMixin knowledgeFabric API knowledgeVPFX core runtime source editing4. Create the pack folder
Create a folder named:
example_minimal_pack/Inside it, create this structure:
example_minimal_pack/├─ pack.json├─ post_effect/│ └─ main.json└─ shaders/ └─ composite/ ├─ final.vsh └─ final.fshThe names are not special, but this guide will use:
pack_id: example_minimal_packentry file: post_effect/main.jsonshader path: composite/finalKeep the first pack boring. A boring first pack is good because it lets you confirm that the pipeline works.
5. Write pack.json
Create:
pack.jsonExample:
{ "format_version": 1, "pack_id": "example_minimal_pack", "name": "Example Minimal VPFX Pack", "version": "1.0.0", "author": "Your Name", "description": "A minimal VPFX post-processing pack.", "entry_post_effect": "post_effect/main.json", "capabilities": { "scene_color": true, "scene_depth": false, "shadow_depth": false, "custom_targets": true, "compute": false }}Important rules:
pack_id should be lowercase.pack_id should not contain spaces.pack_id should match the namespace used in shader references.entry_post_effect should point to your main post effect graph.Good pack IDs:
example_minimal_packcinematic_tone_packmyname.color_gradedebug-shadow-viewBad pack IDs:
Example PackMy Shader!!!cool pack 1For your first pack, use:
"shadow_depth": falseDo not use shadow_depth until your basic color pass works.
6. Write post_effect/main.json
Create:
post_effect/main.jsonExample:
{ "targets": {}, "passes": [ { "id": "final_composite", "debug_label": "Final Composite", "vertex_shader": "example_minimal_pack:composite/final", "fragment_shader": "example_minimal_pack:composite/final", "inputs": [ { "sampler_name": "In", "target": "minecraft:scene_color" } ], "output": "minecraft:main" } ]}This defines one fullscreen pass.
It reads:
minecraft:scene_colorIt writes:
minecraft:mainThe shader reference:
example_minimal_pack:composite/finalmaps to:
shaders/composite/final.vshshaders/composite/final.fshThe part before : is the pack namespace.
The part after : is the path inside the shaders/ folder.
7. Write final.vsh
Create:
shaders/composite/final.vshUse this fullscreen triangle vertex shader:
#version 150
out vec2 texCoord;
void main() { vec2 pos;
if (gl_VertexID == 0) { pos = vec2(-1.0, -1.0); } else if (gl_VertexID == 1) { pos = vec2(3.0, -1.0); } else { pos = vec2(-1.0, 3.0); }
texCoord = pos * 0.5 + 0.5; gl_Position = vec4(pos, 0.0, 1.0);}This draws a fullscreen triangle without needing a vertex buffer.
8. Write final.fsh
Create:
shaders/composite/final.fshUse this minimal fragment shader:
#version 150
uniform sampler2D InSampler;
in vec2 texCoord;out vec4 fragColor;
void main() { vec4 color = texture(InSampler, texCoord); fragColor = color;}This shader does nothing visually. It copies the scene color to the output.
That is intentional.
Your first goal is not to make a beautiful effect. Your first goal is to confirm that the pack loads and renders correctly.
9. Understand sampler names
In main.json, you wrote:
{ "sampler_name": "In", "target": "minecraft:scene_color"}In GLSL, that becomes:
uniform sampler2D InSampler;The naming pattern is:
<sampler_name>SamplerExamples:
In -> InSamplerColor -> ColorSamplerScene -> SceneSamplerDepth -> DepthSamplerShadow -> ShadowSamplerIf your sampler name and GLSL uniform do not match, your pack may fail or render incorrectly.
10. Zip the pack correctly
When you zip the pack, pack.json must be at the root of the zip.
Correct:
example_minimal_pack.zip├─ pack.json├─ post_effect/│ └─ main.json└─ shaders/ └─ composite/ ├─ final.vsh └─ final.fshIncorrect:
example_minimal_pack.zip└─ example_minimal_pack/ ├─ pack.json ├─ post_effect/ │ └─ main.json └─ shaders/ └─ composite/ ├─ final.vsh └─ final.fshThe second structure has an extra nested folder. VPFX may not detect it correctly.
11. Install the pack
Copy the zip file to:
.minecraft/shaderpacks/Then start Minecraft with VPFX installed.
Open the VPFX shaderpack menu:
F7Select your pack.
Click Done.
If the pack loads, the screen should look the same as vanilla because your shader currently only copies the scene color.
That is a successful first test.
12. Reload while editing
After changing your shader files, rebuild the zip and reload the pack.
Default reload key:
F10Command:
/vpfx reloadUseful commands:
/vpfx list/vpfx reload/vpfx reload auto/vpfx reload builtin/vpfx offA typical edit loop is:
Edit final.fshZip the pack againCopy it to shaderpacks/Press F10 in-gameCheck the resultRepeatLater, tooling can make this faster, but the manual loop is enough for the first pack.
13. Make your first visible effect
Once the copy pass works, modify final.fsh.
Try this:
#version 150
uniform sampler2D InSampler;
in vec2 texCoord;out vec4 fragColor;
void main() { vec4 color = texture(InSampler, texCoord);
float contrast = 1.08; vec3 result = (color.rgb - 0.5) * contrast + 0.5;
result *= vec3(1.04, 0.99, 0.94);
fragColor = vec4(result, color.a);}This adds a small contrast boost and a slight warm tone.
If you see the image change, your VPFX pack is working.
14. Add a simple vignette
Try this version:
#version 150
uniform sampler2D InSampler;
in vec2 texCoord;out vec4 fragColor;
void main() { vec4 color = texture(InSampler, texCoord);
vec3 result = color.rgb;
float contrast = 1.06; result = (result - 0.5) * contrast + 0.5;
result *= vec3(1.04, 0.98, 0.92);
float dist = length(texCoord - vec2(0.5)); float vignette = 1.0 - smoothstep(0.42, 0.78, dist);
result *= mix(0.72, 1.0, vignette);
fragColor = vec4(result, color.a);}This is still a single-pass effect.
It uses only:
minecraft:scene_colorIt does not use scene depth or shadow depth.
15. Recommended first-pack rules
For your first VPFX pack:
Use one pass.Use only scene_color.Output to minecraft:main.Do not use custom targets yet.Do not use scene_depth yet.Do not use shadow_depth yet.Do not use history buffers yet.Do not use compute.This keeps debugging simple.
Once this works, you can gradually add complexity.
16. Common issue: pack does not appear
Check:
The zip is inside .minecraft/shaderpacks/.pack.json is at the root of the zip.pack.json is valid JSON.pack_id is valid.The file extension is .zip.The pack is not inside an extra nested folder.Also check the game log:
.minecraft/logs/latest.logSearch for:
VPFX17. Common issue: shader is missing
If the shader cannot be found, check your shader reference.
In main.json:
"fragment_shader": "example_minimal_pack:composite/final"This must match:
pack_id = example_minimal_packfile = shaders/composite/final.fshAlso check:
Is the folder named shaders, not shader?Is the file extension .fsh, not .frag?Is the path lowercase and consistent?Does final.vsh exist too?18. Common issue: black screen
A black screen usually means one of these happened:
The shader failed to compile.The fragment shader did not write fragColor.The sampler uniform name is wrong.The pass did not output to minecraft:main.The pack read from an invalid target.The pack has a JSON syntax error.Check latest.log first.
Also try returning a constant color:
#version 150
in vec2 texCoord;out vec4 fragColor;
void main() { fragColor = vec4(1.0, 0.0, 1.0, 1.0);}If the screen becomes magenta, the shader is running. If not, the pass is probably not executing or the shader failed to compile.
19. Common issue: sampler does not work
If this does not work:
uniform sampler2D In;Use this instead:
uniform sampler2D InSampler;The sampler name from JSON gets Sampler appended in GLSL.
JSON:
"sampler_name": "In"GLSL:
uniform sampler2D InSampler;20. Common issue: JSON syntax
JSON does not allow trailing commas.
Invalid:
{ "format_version": 1, "pack_id": "example_minimal_pack",}Valid:
{ "format_version": 1, "pack_id": "example_minimal_pack"}If the pack suddenly disappears after editing JSON, check for:
Trailing commasMissing commasMissing quotesWrong bracketsInvalid file encoding21. About custom targets
A custom target is an intermediate render target used between passes.
You do not need custom targets for your first pack.
Later, custom targets are useful for:
BlurBloomMulti-pass tone mappingTemporal effectsDebug overlaysDownsample / upsample chainsA future document will explain targets and multi-pass graphs in detail.
For now, keep:
"targets": {}and write directly to:
minecraft:main22. About scene_depth
minecraft:scene_depth is the main camera depth.
It can be used for:
Fog effectsDepth-based color gradingDepth debug viewsUnderwater or distance effectsOutline-like effectsDo not use it in your first pack. Depth requires understanding depth format and reconstruction rules.
Use scene color first.
23. About shadow_depth
shadow_depth is VPFX shadow map depth.
It may include:
Terrain castersEntity castersPlayer castersBlock entity castersImportant:
shadow_depth is not the same as scene_depth.shadow_depth is not main camera depth.shadow_depth uses shadow-space coordinates.shadow_depth uses reversed-Z.shadow_depth is based on shadowOrigin-relative world positions.Do not use shadow_depth in your first pack.
Read the dedicated VPFX shadow_depth Guide before writing custom shadow receivers.
24. What to share when asking for help
When asking for help with a pack, include:
Your pack zipVPFX versionMinecraft versionA screenshot of the problemlatest.logWhat you expected to happenWhat actually happenedIf the issue is shader-related, also include:
pack.jsonpost_effect/main.jsonThe shader file that failsA good help request:
I am making a single-pass color grading pack. The pack appears in the VPFX menu, but selecting it gives a black screen. I expected the image to become warmer. latest.log shows a shader compile error near line 12 in final.fsh. Pack zip attached.A bad help request:
my pack broken25. Suggested first pack ideas
Good first packs:
Warm tone packCold tone packHigh contrast packLow saturation packSimple vignette packNight visibility test packDepth-free cinematic packDebug solid color packAvoid these for your first pack:
Full shadow receiverBloom chainTemporal accumulationMotion blurScreen-space reflectionsComplex depth reconstructionIris shaderpack portStart small. Make one thing work. Then add one more thing.
26. Pack author checklist
Before sharing your pack, check:
Does pack.json exist at the zip root?Does pack_id match your shader namespace?Does the pack appear in the VPFX menu?Does it load without errors?Does F10 reload work?Does /vpfx off recover vanilla rendering?Does the pack output to minecraft:main?Does latest.log contain VPFX errors?Did you test in at least one normal world?Did you test day and night if your effect changes brightness?27. Recommended development path
A good learning path:
1. Minimal copy pass2. Simple color grading3. Vignette4. Multiple passes5. Custom targets6. Scene depth7. Shadow depth8. Shadow receiver9. Showcase packDo not skip straight to step 7.
Most pack authoring problems become easier once you understand steps 1–5.
28. Final goal
By the end of this guide, you should have:
A valid VPFX pack zipA working pack.jsonA working post_effect/main.jsonA fullscreen vertex shaderA fragment shader that modifies scene colorA pack that appears in the VPFX menuA pack that reloads with F10Once you have that, you are ready for the next document:
03 - Pack Manifest FormatThat document will explain every pack.json field in detail.