water-fluid-shaders — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited water-fluid-shaders (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Use this skill when the user wants to create, modify, or optimize water, ocean, river, lake, pond, fluid, lava, or liquid shaders in Unity — especially for mobile or WebGL. Triggers include: "water shader", "ocean", "waves", "foam", "shoreline", "refraction", "caustics", "Gerstner", "fluid", "depth coloring", "stylized water", "toon water", or references to any water-related visual effect. Also trigger when the user references NVJOB, bmjoy, or Alexander Ameye water shader repos.
This template provides a production-ready starting point for mobile water:
Shader "Mobile/Water_Simple"
{
Properties
{
_ShallowColor ("Shallow Color", Color) = (0.3, 0.8, 0.9, 0.6)
_DeepColor ("Deep Color", Color) = (0.1, 0.2, 0.5, 0.9)
_DepthMaxDistance ("Depth Max Distance", Float) = 3.0
_NormalMap ("Normal Map", 2D) = "bump" {}
_NormalScale ("Normal Scale", Float) = 0.5
_WaveSpeed ("Wave Speed", Float) = 0.05
_FoamColor ("Foam Color", Color) = (1, 1, 1, 1)
_FoamDistance ("Foam Distance", Float) = 0.4
_FoamCutoff ("Foam Cutoff", Float) = 0.5
}
SubShader
{
Tags {
"RenderType" = "Transparent"
"Queue" = "Transparent"
"RenderPipeline" = "UniversalPipeline"
}
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
CBUFFER_START(UnityPerMaterial)
half4 _ShallowColor;
half4 _DeepColor;
half _DepthMaxDistance;
float4 _NormalMap_ST;
half _NormalScale;
half _WaveSpeed;
half4 _FoamColor;
half _FoamDistance;
half _FoamCutoff;
CBUFFER_END
TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap);
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
float3 positionWS : TEXCOORD2;
};
Varyings vert(Attributes v)
{
Varyings o;
VertexPositionInputs posInputs = GetVertexPositionInputs(v.positionOS.xyz);
o.positionCS = posInputs.positionCS;
o.positionWS = posInputs.positionWS;
o.screenPos = ComputeScreenPos(o.positionCS);
o.uv = TRANSFORM_TEX(v.uv, _NormalMap);
return o;
}
half4 frag(Varyings i) : SV_Target
{
// --- Depth-based coloring ---
float2 screenUV = i.screenPos.xy / i.screenPos.w;
float rawDepth = SampleSceneDepth(screenUV);
float sceneEyeDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
float surfaceEyeDepth = i.screenPos.w;
half depthDiff = saturate((sceneEyeDepth - surfaceEyeDepth) / _DepthMaxDistance);
half4 waterColor = lerp(_ShallowColor, _DeepColor, depthDiff);
// --- Animated normal map (single sample) ---
float2 scrollUV = i.uv + _Time.y * _WaveSpeed;
half3 normal = UnpackNormalScale(
SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, scrollUV),
_NormalScale
);
// --- Shoreline foam ---
half foamDepth = saturate((sceneEyeDepth - surfaceEyeDepth) / _FoamDistance);
half foam = step(foamDepth, _FoamCutoff);
waterColor = lerp(waterColor, _FoamColor, foam * _FoamColor.a);
// --- Simple fresnel ---
half3 viewDir = normalize(_WorldSpaceCameraPos - i.positionWS);
half fresnel = pow(1.0h - saturate(dot(half3(0, 1, 0), viewDir)), 3.0h);
waterColor.a = lerp(waterColor.a, 1.0h, fresnel);
return waterColor;
}
ENDHLSL
}
}
Fallback "Universal Render Pipeline/Unlit"
}Gerstner waves produce realistic trochoidal wave motion. Compute in vertex shader only:
// Add to vertex shader — call for each wave octave
float3 GerstnerWave(float3 worldPos, float2 direction, float steepness,
float wavelength, float speed)
{
float k = 2.0 * PI / wavelength;
float c = sqrt(9.8 / k); // Phase speed from dispersion relation
float2 d = normalize(direction);
float f = k * (dot(d, worldPos.xz) - c * speed * _Time.y);
float a = steepness / k; // Amplitude
return float3(
d.x * a * cos(f),
a * sin(f),
d.y * a * cos(f)
);
}
// In vertex shader:
Varyings vert(Attributes v)
{
float3 worldPos = TransformObjectToWorld(v.positionOS.xyz);
// 2-3 wave octaves for mobile (vary direction, wavelength, steepness)
float3 wave1 = GerstnerWave(worldPos, float2(1, 0.5), 0.25, 8.0, 1.0);
float3 wave2 = GerstnerWave(worldPos, float2(0.3, 1), 0.15, 4.0, 1.2);
worldPos += wave1 + wave2;
// Recalculate normals from wave tangent/binormal
// (simplified — use cross product of partial derivatives)
Varyings o;
o.positionCS = TransformWorldToHClip(worldPos);
// ... rest of vertex setup
return o;
}Use this to decide which features fit your mobile budget:
For Shader Graph users, here's the node-efficient approach to mobile water:
Total node budget: Keep under 60 nodes for the water shader on mobile. Use Sub Graphs to organize — they don't add overhead but keep the graph readable.
These are the best open-source water shaders to reference:
| Repo | Mobile? | Features | License |
|---|---|---|---|
| nvjob/nvjob-water-shader-simple-and-fast | YES | Normal mapping, parallax, no tessellation | MIT |
| nvjob/nvjob-water-shaders-v2 | YES | V1 + reflections + shoreline foam | MIT |
| bmjoy/Stylized-Water-Shader-Unity-URP | YES | URP, depth color, foam, refraction | — |
| N7RX/Simple-Water-Shader | YES | Lightweight mobile-first | — |
| danielshervheim/unity-stylized-water | Partial | Stylized with material presets (~953★) | — |
| MatrixRex/Uber-Stylized-Water | Partial | Unity 6, highly customizable | — |
| tuxalin/water-shader | No | Multi-platform, Gerstner, caustics | — |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.