{"id":46657104,"url":"https://github.com/metashade/metashade","last_synced_at":"2026-04-01T22:25:47.147Z","repository":{"id":41440451,"uuid":"106956447","full_name":"metashade/metashade","owner":"metashade","description":"An experimental GPU shading DSL embedded in Python.","archived":false,"fork":false,"pushed_at":"2026-03-20T00:18:07.000Z","size":709,"stargazers_count":77,"open_issues_count":26,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-20T15:38:55.514Z","etag":null,"topics":["computer-graphics","dsl","edsl","metaprogramming","metashade","python","shaders","shading-language"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/metashade.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2017-10-14T19:26:02.000Z","updated_at":"2026-03-20T00:18:11.000Z","dependencies_parsed_at":"2023-10-27T00:33:09.075Z","dependency_job_id":"380c752c-5b64-4f1e-a9f3-ed5c42416825","html_url":"https://github.com/metashade/metashade","commit_stats":null,"previous_names":["metashade/metashade"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/metashade/metashade","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metashade%2Fmetashade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metashade%2Fmetashade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metashade%2Fmetashade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metashade%2Fmetashade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metashade","download_url":"https://codeload.github.com/metashade/metashade/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metashade%2Fmetashade/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["computer-graphics","dsl","edsl","metaprogramming","metashade","python","shaders","shading-language"],"created_at":"2026-03-08T08:34:05.946Z","updated_at":"2026-04-01T22:25:47.138Z","avatar_url":"https://github.com/metashade.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Metashade\n## What is Metashade?\nMetashade is an experimental Python-based GPU shading embedded domain-specific language (EDSL).\nWhen a Metashade script executes, it generates code in a target shading language.\nCurrently, limited but useful subsets of HLSL and GLSL are supported, and more targets are possible in the future.\n\nTo see Metashade in action, check out the glTF demo at https://github.com/metashade/metashade-glTFSample or the [tests](tests) which are run by CI:\n[![GitHub Actions CI](https://github.com/metashade/metashade/actions/workflows/python-package.yml/badge.svg)](https://github.com/metashade/metashade/actions/workflows/python-package.yml)\n\nThere's also a prototype [MaterialX](https://materialx.org/) integration that allows Metashade to generate MaterialX node implementations. See the [`metashade.mtlx` package](metashade/mtlx) and the [mtlx tests](tests/mtlx) for examples.\n\nFor a detailed discussion of the motivation for Metashade and its design, please see the [presentation on Google Slides](https://docs.google.com/presentation/d/e/2PACX-1vQtYIwXIkMnVC6TzWTKPAtZIA6_xeUCQc8Mvyziu0qy7HDUduz_onsJ5TabxTuuVQ/pub?start=false\u0026loop=false\u0026delayms=3000) or [watch this presentation](https://youtu.be/yC8VMLXYs5U?si=d_n3ngHr1IZIQ8ZH) from Academy Software Foundation Open Source Days 2024.\n\n## Rationale\n\n* Programming at a more abstract level than the target language:\n    * Metaprogramming - think C++ templates but with greater flexibility.\n    Like any other Python code, Metashade code is polymorphic at generation time.\n    This approach can replace the traditional ubershader practice, effectively replacing the C preprocessor with Python.\n    * Stricter typing - e.g. a 3D point and an RGB color can be represented with different Metashade types, backed by the same data type in HLSL.\n* Multi-language/cross-platform support.\n    Cross-compilation (e.g. with SPIRV-Cross) is definitely an alternative but the code generation approach should offer higher flexibility around:\n    * more divergent languages, e.g. HLSL vs OSL;\n    * language dialects;\n    * integration required by the specific host application (a shader fragment with an interface defined in metadata, an effect file etc.),\n    which is hard to accomplish with cross-compilation because it typically operates on final,\n    full shaders with a defined entry point.\n* Easy integration with content pipeline and build system scripts written in Python, and the vast Python ecosystem in general.\n\n## What does it look like?\n\nThe following Metashade Python code\n\n```Python\n@export\ndef D_Ggx(sh, NdotH: 'Float', fAlphaRoughness: 'Float') -\u003e 'Float':\n    \"\"\"\n    GGX/Trowbridge-Reitz Normal Distribution Function.\n    \n    Args:\n        NdotH: Dot product of surface normal and half-vector\n        fAlphaRoughness: Roughness parameter (perceptualRoughness^2)\n    \n    Returns:\n        NDF value\n    \"\"\"\n    sh.fASqr = fAlphaRoughness * fAlphaRoughness\n    sh.fF = (NdotH * sh.fASqr - NdotH) * NdotH + sh.Float(1.0)\n    sh.return_(\n        (sh.fASqr / (sh.Float(math.pi) * sh.fF * sh.fF)).saturate()\n    )\n```\n\ngenerates the following HLSL output:\n\n```C\n// GGX/Trowbridge-Reitz Normal Distribution Function.\n// \n// Args:\n// NdotH: Dot product of surface normal and half-vector\n// fAlphaRoughness: Roughness parameter (perceptualRoughness^2)\n// \n// Returns:\n// NDF value\n//\nfloat D_Ggx(float NdotH, float fAlphaRoughness)\n{\n\tfloat fASqr = fAlphaRoughness * fAlphaRoughness;\n\tfloat fF = (((NdotH * fASqr) - NdotH) * NdotH) + 1.0;\n\treturn saturate(fASqr / ((3.141592653589793 * fF) * fF));\n}\n```\n\n## How does it work?\n\nPopular Pythonic GPU EDSLs like [Nvidia Warp](https://github.com/NVIDIA/warp),\n[Taichi](https://github.com/taichi-dev/taichi),\n[Numba](https://github.com/numba/numba)\nand [OpenAI’s Triton](https://github.com/openai/triton)\nrely on Python's introspection to capture the Python AST and transpile it to the target language.\nThis approach can only support a subset of Python syntax that maps onto the target language.\n\nIn contrast, Metashade generates target code dynamically, during the execution of Python code,\nmodeling the state of the shader being generated in objects called generators.\nThis requires some idiosyncratic Python syntax but in return we get the full power of Python at generation time.\nPython's run time becomes the shader's design time, and it becomes a metaprogramming language, independent of the target language and replacing mechanisms like the C Preprocessor, generics and templates.\n\nThis offers the following benefits:\n* Easy-to-use metaprogramming. Imperative metaprogramming is possible (by comparison, C++ templates are a pure-functional language).\n* The whole stack is debuggable by the application programmer.\n* Codegen can interact with the outside world (file system or user input). E.g. the [glTF demo](https://github.com/metashade/metashade-glTFSample) loads glTF assets and generates shaders based on their contents.\n* Codegen can integrate with arbitrary Python code. E.g. the [glTF demo](https://github.com/metashade/metashade-glTFSample) uses the third-party [pygltflib](https://pypi.org/project/pygltflib/) to parse glTF assets.\n* It's easy to build abstractions on top of basic codegen.\n\n### Creating a generator\n\nBefore Metashade can generate anything, a generator object has to be created for a specific target shading\nlanguage profile, with an output file (or a file-like stream object) passed as a constructor argument, e.g.\n\n```Python\nfrom metashade.hlsl.sm6 import ps_6_0\nfrom metashade.glsl import frag\n\ndef generate(sh):\n    # Polymorphic shader code for multiple targets\n    pass\n\nwith open('ps.hlsl', 'w') as ps_file:\n    sh = ps_6_0.Generator(ps_file)\n    generate(sh)\n\nwith open('fs.glsl', 'w') as frag_file:\n    sh = frag.Generator(frag_file)\n    generate(sh)\n```\n\nNote that, by convention, the generator object is always named `sh` (for \"shader\").\nThis helps Metashade code be polymorphic with regard to different target profiles.\nE.g. code with the same logic can be generated for an HLSL pixel shader and a GLSL compute shader.\n\n### Generating C-like scopes and local variables\n\nMetashade uses Python variables to represent variables in target C-like shading languages,\nbut there are obviously major differences in their behavior, namely:\n* C-like languages have different scoping rules than Python.\n* In Python, variables are always assigned by reference and the same variable can point to different objects, possibly of different types in its lifetime.\nVariables in C-like shading languages, in contrast, are typed statically and are assigned by value.\n\nThe following Python mechanisms are used in Metashade to emulate the C-like semantics at Python code's run time.\n\n#### `with` statements\n\nMetashade uses Python's `with` statements to emulate C-like scopes.\nFor example, in a [function definition](#what-does-it-look-like), the `sh.function` object starts a new scope by modifying the internal state of generator `sh` when its special `__enter__` and `__exit__` methods are called.\n\n#### `__getattr__` and `__setattr__`\n\nTo model the semantics of target variables, Metashade exposes them syntactically as member variables on the generator object (hence the idiosyncratic `sh.x` syntax).\nThis is implemented with the special `__getattr__` and `__setattr__` functions, which overload member accesses.\nWith these, we have complete control over the variable's lifetimes and typing.\nFor example, we can capture the variable's name with `__setattr__()` without the need for Python introspection.\nWe can also easily check in `__setattr__()` if the user is trying to reinitialize the variable with a different type, and we can raise an exception in `__getattr__()` if the user tries to access a variable that's gone out of scope.\n\nThe `__getattr__()`/`__setattr__()` mechanism is also used for other features, such as accessing struct members and vector elements.\n\n#### Operator overloading\n\nJust like in C++, Python's operators can be overloaded with arbitrary logic.\nMetashade uses this feature to model expressions in the target language - something along the lines of\n\n```Python\ndef __add__(self, other):\n    return Expression(f\"{self} + {other}\")\n```\n\nThis also opens up possibilities for injecting custom logic, such as stronger type checks, independent from the target language.\nE.g. `sh.RgbF` can’t be added to `sh.Point3f` even though they're both backed by the `float3` built-in type in HLSL.\n\nFor added syntactic sugar, the `__floordiv__` operator is overloaded to generate comments in the target language (see below).\n\n## Some examples\n\nThe following Python code\n\n```Python\nsh.rgba = sh.RgbaF(rgb = (0, 1, 0), a = 0)\n\nsh // 'Swizzling - the destination type is deduced'\nsh // \"a-la `auto` in C++\"\nsh.color = sh.rgba.rgb\n\nsh // 'Write masking'\nsh.color.r = 1\n\nsh // 'Intrinsics example'\nsh.N = sh.N.normalize()\n\nsh // 'Dot product == Python 3 matmul'\nsh // '(a.k.a. \"walrus\") operator'\nsh.NdotL = sh.N @ sh.L\n\n# The walrus operator is also used to\n# combine textures and samplers\ncombined_sampler = sh.g_tColor @ sh.g_sColor\n\nsh // 'Sample the texture'\nsh.rgbaSample = combined_sampler(sh.uv)\n```\n\ngenerates the following HLSL:\n\n```HLSL\nfloat4 rgba = float4(float3(0, 1, 0), 0);\n\n// Swizzling - the destination type is deduced\n// a-la `auto` in C++\nfloat3 color = rgba.rgb;\n\n// Write masking\ncolor.r = 1;\n\n// Intrinsics example\nN = normalize(N);\n\n// Dot product == Python 3 matmul\n// (a.k.a. \"walrus\") operator\nfloat NdotL = dot(N, L);\n\n// Sample the texture\nfloat4 rgbaSample = g_tColor.Sample(g_sColor, uv);\n```\n\n### Conditional statements\n\nMetashade models `if` and `else` statements of the target C-like languages with Python's `with` statements, for example:\n\n```Python\n    with sh.if_(sh.g_f4A.x):\n        sh.result.color = sh.g_f4B\n    with sh.else_():\n        sh.result.color = sh.g_f4D\n    sh.return_(sh.result)\n```\n\ngenerates the following HLSL:\n\n```HLSL\n    if (g_f4A.x)\n    {\n        result.color = g_f4B;\n    }\n    else\n    {\n        result.color = g_f4D;\n    }\n    return result;\n```\n\nPlease note that the native Python `if` and `else` can be used in Metashade to implement design-time logic, similar to `#ifdef` or `if constexpr()` in C++.\nThis is another example of how Metashade explicitly separates design-time and run-time code.\n\nFor example, the following code is generated conditionally if the input geometry has vertex tangents:\n\n```Python\n    if hasattr(sh.vsIn, 'Tobj'):\n        sh.vsOut.Tw = sh.g_WorldXf.xform(sh.vsIn.Tobj.xyz).xyz.normalize()\n        sh.vsOut.Bw = sh.vsOut.Nw.cross(sh.vsOut.Tw) * sh.vsIn.Tobj.w\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetashade%2Fmetashade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetashade%2Fmetashade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetashade%2Fmetashade/lists"}