0.0
The project is in a healthy, maintained state
Lets you write WebGL2 rendering code entirely in Ruby, running under ruby.wasm in the browser. Resolves uniform/attribute locations from a glslkit reflection manifest instead of calling getActiveUniform, and surfaces shader compile errors as Ruby exceptions pointing at the original file and line. REQUIRES a ruby.wasm runtime (the `js` gem) to run — it installs under a normal CRuby/JRuby/TruffleRuby, but raises a clear LoadError instead of working there. This gem is meant to be bundled into a ruby.wasm build (see README), not required from a regular Ruby process.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

~> 0.1.0
 Project Readme

glslkit

GLSLの #include 解決とリフレクション抽出を行うRuby gem。シェーダのコンパイル エラーが、#include先の元ファイル名と行番号を持ったRubyの例外として上がる。

CompileErrorがcommon/sdf.glsl:5を指しているneon-error.htmlの画面

なぜこれが要るのか

GLSLには #include が無く、シェーダをファイル単位でモジュール分割できない。 コピー&ペーストで共通コードを重複させるか、1ファイルに書き殴るかの二択になりやすい。 また、コンパイルエラーはドライバから「平坦化後の行番号」でしか返らないため、 #includeを手動展開している場合、エラー行から元のファイルを探し当てるのは それ自体が調査作業になる。glslkitは#include解決を肩代わりし、平坦化前の ファイル名・行番号をエラーに復元して返す。

構成

1リポジトリ・3gem構成。core/が将来 ruby.wasm にバンドルされる際、Rails側のコードと依存を持ち込まないための分離。

gem ディレクトリ 実行時依存 内容
glslkit core/ なし #include解決、リフレクション抽出、マニフェスト生成
glslkit-rails rails/ glslkit, railties >= 7.1, propshaft >= 1.3.2 Propshaft統合、ビューヘルパー、ライブリロード
glslkit-webgl webgl/ glslkit ruby.wasm上で動くWebGL2ランタイム(ブラウザ向け)
glslkit/
├── core/                             # gem: glslkit
├── rails/                            # gem: glslkit-rails
├── webgl/                            # gem: glslkit-webgl
├── examples/rails-demo/              # ライブリロードの実演用Railsアプリ
└── spec/schema/reflection-v1.json    # JSON Schema (Draft 2020-12)

インストールと最小の使用例

gem "glslkit"
require "glslkit"

resolver = Glslkit::Resolvers::FileSystem.new(load_paths: ["app/shaders"])
source   = Glslkit::Preprocessor.new(resolver: resolver).process("pbr.frag")

source.code        # => 平坦化済みGLSL (String)。#include解決済み、#lineディレクティブ付き
source.reflection  # => Glslkit::Reflection (attributes / uniforms / uniform_blocks / outputs)
source.digest       # => SHA256 hex (String)

Railsで使う場合、wasm上でWebGLを扱う場合はそれぞれのREADMEを参照:

  • core/README.md — #include解決、リフレクション抽出、マニフェスト生成の詳細
  • rails/README.md — Propshaft統合、ビューヘルパー、rakeタスク
  • webgl/README.md — ruby.wasm上でのWebGL2ランタイム、rbwasmでのパッケージング

glslkit-webglのページはfile://ではなくHTTP経由で開くこと。 ruby.wasmが エントリの.rbをfetchで読み込むため、file://ではSafariが確実に失敗する (Fetch API cannot load file:///... due to access control checks.)。Chromeは 現状緩めに動くが将来同じ制限が入る可能性がある。python3 -m http.server 8000 等でローカルサーバを立ててhttp://localhost:8000/...として開くこと(詳細は webgl/README.md参照)。

ライブリロード

.glsl/.vert/.fragを保存すると、ページをリロードせずにシェーダだけ 差し替わる。壊すと直前の描画を保ったまま元ファイル名・行番号でエラーが出て、 直すとリロード無しで復帰する。実際に動かして試せる最小Railsアプリを examples/rails-demo/に用意している (development専用)。

実測値(Chrome)

  • 描画: 60fps / 30秒1801フレームでフレーム落ちゼロ / 最悪フレーム17.7ms
  • GC: 計測中に12回発生したが、発生フレームも通常フレームと区別がつかなかった

起動コスト

ruby.wasmのバイナリ(ruby+stdlib.wasm)は約9MBある。

  • 初回訪問(キャッシュ無し): 約9MBの転送 + 起動まで中央値約1,130ms
  • 2回目以降(HTTPキャッシュ有効): 中央値117〜178ms(fetch+compile / VM初期化 / 最初の行の実行、の合計。計測環境により倍近い差が出る)

いずれもChrome実測。ネットワーク環境により初回は大きく変動する。

ruby.wasmにはstdlibを絞ったビルドもあり、glslkit-webglが実際に使うstdlibは 限られるため、カスタムビルドで転送量を減らせる可能性がある(未検証)。

できないこと

以下は実測に基づく制約であり、設計上の欠陥ではない(詳細は webgl/README.md参照):

  • 毎フレームの頂点データ更新
  • CPUスキニング
  • モーフターゲットのCPU補間
  • パーティクル(CPU側で毎フレーム更新するもの)

100,000要素の転送だけで18.8msかかり、60fpsのフレーム予算を超える。 ジオメトリは静的に保ち、変形はシェーダ側(GPU)で行い、行列やウェイトだけを uniformとして送ること。

検証環境

  • Chrome: 描画・フレーム安定性・起動コスト・ライブリロードを実測
  • Safari: 描画のみ確認(neonサンプルが正しく動作)。フレーム性能とライブリロードは未計測

いずれもmacOS。他のブラウザ・OSは未確認。

ライセンス

MIT