{
  "name": "Smoke",
  "dimension": "3d",
  "slot": "action_bar",
  "width": 256,
  "height": 128,
  "textBaseline": 128,
  "placement": {
    "x": 0,
    "y": 0
  },
  "shapes": [],
  "texts": [],
  "heads": [],
  "images": [],
  "bars": [],
  "triggers": [],
  "world": {
    "glsl": "const int STATE_IDLE = 0;\nconst int STATE_DISTURBED = 1;\nconst int STATE_DEPLOY = 2;\nconst int STATE_DISSIPATE = 3;\n\n// Value and analytic gradient; integer lattice offsets keep shared corners identical.\nvec4 smokeNoise(vec3 x) {\n    vec3 i = floor(x);\n    vec3 f = fract(x);\n    vec3 u = f * f * (3.0 - 2.0 * f);\n    vec3 du = 6.0 * f * (1.0 - f);\n    float h = dot(i, vec3(1.0, 57.0, 113.0));\n    vec4 a = fract(sin(h + vec4(0.0, 1.0, 57.0, 58.0)) * 43758.5453);\n    vec4 b = fract(sin(h + vec4(113.0, 114.0, 170.0, 171.0)) * 43758.5453);\n    vec4 c = mix(a, b, u.z);\n    float lo = mix(c.x, c.y, u.x);\n    float hi = mix(c.z, c.w, u.x);\n    float v = mix(lo, hi, u.y);\n    float dx = mix(c.y - c.x, c.w - c.z, u.y) * du.x;\n    float dy = (hi - lo) * du.y;\n    vec4 z = b - a;\n    float dz = mix(mix(z.x, z.y, u.x), mix(z.z, z.w, u.x), u.y) * du.z;\n    return vec4(v, dx, dy, dz);\n}\nfloat smokeRest(int state) {\n    return state == STATE_DISSIPATE ? 0.0 : 1.0;\n}\nvec4 object(vec3 ro, vec3 rd, float t0, float t1, float time, vec3 light, inout float depth) {\n    float age = min(rpw_state_time, 1000.0);\n    float life = 1.0;\n    float scale = 1.0;\n    if (rpw_state == STATE_DEPLOY) {\n        float k = smoothstep(0.0, 2.5, age);\n        life = mix(smokeRest(rpw_prev_state), 1.0, k);\n        if (rpw_prev_state == STATE_DISSIPATE) scale = mix(0.12, 1.0, k);\n    }\n    if (rpw_state == STATE_DISSIPATE) life = mix(smokeRest(rpw_prev_state), 0.0, smoothstep(0.0, 5.0, age));\n    if (rpw_state == STATE_IDLE || rpw_state == STATE_DISTURBED) life = mix(smokeRest(rpw_prev_state), 1.0, smoothstep(0.0, 1.2, age));\n    if (life < 0.001) return vec4(0.0);\n    // A scripted passage, not entity detection: this contract has no entity transforms.\n    float disturb = 0.0;\n    if (rpw_state == STATE_DISTURBED) disturb = smoothstep(0.0, 0.55, age) * (1.0 - smoothstep(2.3, 6.5, age));\n    float head = mix(-1.05, 1.05, smoothstep(0.0, 3.0, age));\n    vec3 key = normalize(vec3(-0.45, 0.82, 0.35));\n    vec3 drift = vec3(0.16 * time, -0.27 * time, 0.09 * time) + vec3(11.37 * rpw_seed, 3.2, 0.0);\n    // These do not change between samples.\n    vec3 waveDrift = vec3(-time * 0.55, time * 0.43, time * 0.27);\n    vec3 sampleRo = ro / scale;\n    vec3 sampleRd = rd / scale;\n    float stepLen = (t1 - t0) / 32.0;\n    float extinctionStep = stepLen * 22.0;\n    vec3 ambientTint = vec3(0.69, 0.71, 0.72) * light;\n    vec3 sunlightTint = vec3(0.80, 0.79, 0.75) * 0.68 * light;\n    float trans = 1.0;\n    vec3 sum = vec3(0.0);\n    bool setDepth = false;\n    bool first = true;\n    for (int i = 0; i < 32; i++) {\n        float t = t0 + (float(i) + 0.5) * stepLen;\n        vec3 p = sampleRo + sampleRd * t;\n        float radiusSq = dot(p, p);\n        if (radiusSq > 0.9216) continue;\n        float radius = sqrt(radiusSq);\n        vec3 e = (p - vec3(0.0, -0.065, 0.0)) / vec3(0.89, 0.83, 0.87);\n        float er = length(e);\n        vec4 n = smokeNoise(p * 4.4 + drift);\n        vec3 waves = p.zxy * 16.0 + p.xyz * 7.0 + waveDrift + n.x * 3.0;\n        vec3 s = sin(waves);\n        float fine = s.x * s.y * s.z;\n        float d = er - 0.84 + (n.x - 0.5) * 0.40 + fine * 0.022;\n        float envelope = 1.0 - smoothstep(-0.18, 0.105, d);\n        float den = envelope * (0.78 + 0.36 * n.x);\n        den *= 1.0 - smoothstep(0.89, 0.96, radius);\n        if (disturb > 0.001) {\n            float axial = p.z - clamp(p.z, head - 1.15, head);\n            float vertical = p.y - clamp(p.y, -0.59, -0.25);\n            float hole = length(vec3(p.x, vertical, axial));\n            float wake = 1.0 - smoothstep(0.10, 0.23, hole + fine * 0.012);\n            float refill = 1.0 - 0.55 * smoothstep(0.15, 1.15, head - p.z);\n            den *= 1.0 - wake * disturb * refill;\n            den += 0.12 * envelope * disturb * exp(-pow((hole - 0.23) / 0.075, 2.0));\n        }\n        den *= life;\n        if (den < 0.002) continue;\n        if (first) { depth = t; first = false; }\n        vec3 gradient = e / max(er, 0.001) / vec3(0.89, 0.83, 0.87) + n.yzw * 1.35;\n        float facing = dot(normalize(gradient), key);\n        float thickness = max(0.0, 0.06 - d);\n        float sunlight = exp(-thickness * 5.5 / max(0.36, 0.60 + 0.40 * facing));\n        float ambient = 0.43 + 0.10 * (p.y + 0.75);\n        vec3 shade = ambientTint * ambient + sunlightTint * sunlight;\n        float a = 1.0 - exp(-den * extinctionStep);\n        sum += trans * a * shade;\n        trans *= 1.0 - a;\n        if (!setDepth && trans < 0.70) { depth = t; setDepth = true; }\n        if (trans < 0.006) break;\n    }\n    float alpha = 1.0 - trans;\n    return vec4(sum / max(alpha, 0.0001), alpha);\n}",
    "prompt": "Create a realistic CS2-style smoke grenade. The smoke must form a dense, cohesive, volumetric-looking cloud with soft edges, turbulence and natural movement. When an entity enters or passes through it, dynamically displace the smoke around its body, creating a temporary opening that follows its movement. The smoke must flow back smoothly behind the entity, gradually restoring its original density and shape. Support multiple entities simultaneously, with displacement depending on their size and speed. Avoid simple visibility toggles, flickering or sudden particle popping. Optimize performance for real-time gameplay.",
    "size": 8
  }
}