← デモ解説一覧へ戻る

BABYLON LITE 公式デモを読む

ブラウザの中に、
地獄をもう一度つくる。

WebGPU 専用の軽量 3D エンジン「Babylon Lite」に付属する、名作 FPS「DOOM」の再現デモ。バイナリの WAD を自前で読み解き、当時の“帯状に暗くなる光”まで忠実に描く——GPL コードを一切使わないクリーンルーム実装、全 29 ファイルのしくみを初心者向けにやさしく解説します。

29ファイル
約5,010行のコード
8種のモンスター
35Hzシミュレーション

第1章

このデモとは

「あの1993年の DOOM を、プラグインもエミュレータも使わず、素のブラウザとコードだけで動かせるの?」に、動く実装で答えるサンプルです。

このデモは、Babylon.js ファミリーの WebGPU 専用ランタイム Babylon Lite の公式リポジトリに含まれる、DOOM の再現です。ゲームの中身が入った WAD ファイル(バイナリのデータ塊)をネット越しに読み込み、その中の地図・テクスチャ・スプライト・音を自前のコードで解析して、3D の迷宮として描き、モンスターを動かし、銃を撃てるところまで作り込まれています。

⚖️ クリーンルーム × Freedoom

各ファイルの冒頭には「オリジナルの DOOM エンジン(GPL)のソースは一切参照・複製していない」と明記され、公開仕様(Doom Wiki/Unofficial Doom Specs)だけを頼りにゼロから書き起こしたことが宣言されています。読み込むデータも、権利的にフリーな互換 IWAD Freedoomfreedoom1.wad)。だから安心して中身を読めます。

プログラムとしての見どころは、次の3点です。

📦 バイナリを手で開ける

WAD の12バイトのヘッダから、地図の頂点・線・区画まで、生のバイト列を1つずつ意味に変えていく“データ考古学”。フォーマットの教科書です。

💡 “本物の光”を再現

DOOM 特有の、距離でカクッと帯状に暗くなるあの陰影。RGB を混ぜるのではなく、パレット番号を COLORMAP で引き直すという当時の手法を、そのままシェーダで再現します。

👾 データ駆動のモンスター

敵の見た目も行動も、コードではなく表(テーブル)で定義。「型 → 状態 → 行動」の3段構えで動く、DOOM 名物のアクターシステムを移植しています。

第2章

あそびかた

コードを読む前に、まず走り回るのがいちばんの近道です。操作はオリジナルの DOOM に沿っています。

🎮 ブラウザで遊ぶ

babylonjs.com のライブデモを開く →(WebGPU 対応ブラウザが必要です。初回は WAD の読み込みに少し時間がかかります)

操作すること
前進・後退(移動速度 320 units/秒)
左右に旋回(旋回速度 2.4 rad/秒)
, . / Alt左右に横歩き(ストレイフ)
Shiftダッシュ(移動2倍)
Space使う(扉・スイッチ・リフト)。死亡時はリスポーン
Ctrl / マウス左発砲
17武器切替(拳/ピストル/ショットガン/チェーンガン/ロケット/プラズマ/BFG)
🕹️ マウスルックは無し

オリジナル同様、上下を向く操作はありません(DOOM の世界は高さ方向の照準を“自動”で合わせます)。カメラは地図の高さに沿って動く一人称視点です。

第3章

用語ミニ辞典

この先の章で出てくることばを先にまとめて紹介します。分からなくなったらここに戻ってきてください。

WAD / IWAD

DOOM の全データ(地図・絵・音)を1つに束ねたファイル形式("Where's All the Data")。本体データを IWAD と呼びます。ここでは無料互換の Freedoom を使用。

ランプ(lump)

WAD の中に並ぶ、名前付きのデータの塊1つ1つ。地図・テクスチャ・音などがすべてランプとして格納されています。

BSP(二分空間分割)

地図をあらかじめ木構造に切り分けておく手法。「この点はどの区画にいる?」を高速に答えられ、描画順にも使えます。

セクター / リニデフ / サイドデフ

セクター=床と天井の高さを持つ“部屋”、リニデフ=壁の線、サイドデフ=線に貼るテクスチャ情報。DOOM の地図はこの3つでできています。

フラット / パッチ

フラット=床天井用の 64×64 のタイル画像、パッチ=壁やスプライト用の“列”で圧縮された絵。どちらもパレット番号の並びです。

パレット / COLORMAP

パレット=256色の対応表、COLORMAP=「この明るさなら何色に化けるか」の34段の変換表。DOOM の色と陰影の核心です。

パレットインデックス描画

ピクセルに RGB ではなく“色番号”を持たせ、表を引いて最終色を決める方式。当時のメモリ節約術で、あの独特の陰影の理由でもあります。

mobj(マップオブジェクト)

モンスター・弾・アイテム・置物——動くものすべての共通の器。位置・体力・状態などを持ちます。

ステート / アクション / インフォ

DOOM のアクターは「インフォ(型)→ ステート(アニメの各コマ)→ アクション(AIの関数)」の表で動きます。データ駆動の代表例。

ヒットスキャン

弾を飛ばさず、撃った瞬間に光線で当たり判定する方式。ピストルやショットガンはこれ。ロケットだけは弾(飛翔体)です。

ビルボードスプライト

2Dの絵を常にカメラへ正面を向ける板に貼って“立体っぽく”見せる技。DOOM の敵はすべてこの板です。8方向の絵を使い分けます。

BAM(角度の単位)

Binary Angle Measurement。角度を32bit整数で表す DOOM 流の方法。ビット演算だけで「敵をどの方向から見ているか」を8分割できます。

tic(ティック)

DOOM のシミュレーション1コマ。1秒 = 35 tic固定。描画が速くても遅くても、ゲーム進行は常にこの刻みで進みます。

スペシャル

壁や床に割り当てられた“仕掛け”。扉・リフト・昇降床・スイッチ・出口などを、線と区画の番号で表します。

第4章

全体の地図

エントリの doom.ts(わずか49行)は、エンジンを立ち上げて WAD を取得し、あとは doom-level.ts にレベル作りを丸ごと任せます。

flowchart TD
    ENTRY["doom.ts
エンジン・WAD取得(約28.8MB)"] LEVEL["doom-level.ts
レベルの組み立て役"] subgraph DATA["WADを解く"] WAD["wad/*
バイナリ解析"] end subgraph VIEW["描く"] GEO["geometry/*
壁と床の3D化"] REND["render/*
素材・空・スプライト・武器"] end subgraph SIM["動かす"] MOBJ["mobj/*
アクター(35Hz)"] PLAY["player + combat + physics"] SPEC["specials/*
扉・リフト"] end HUDSND["hud + sound"] ENTRY --> LEVEL LEVEL --> DATA LEVEL --> VIEW LEVEL --> SIM LEVEL --> HUDSND WAD --> GEO WAD --> REND

矢印は「上が下を利用する」向きです。doom-level.ts(309行)が司令塔で、WAD を解いて→静的な壁と床を作り→動く仕掛け・敵・プレイヤーを用意し→毎フレームの更新ループを回します。「読む」「描く」「動かす」がフォルダごとにきれいに分かれているのが、このデモを読むときの最初の目印です。

⏱️ 描画と進行を切り離す

更新ループの心臓は固定タイムステップです。1フレームの経過時間を最大 0.05 秒に抑え、1/35 秒たまるごとに「仕掛け→プレイヤー→世界」を1 tic 進める。だから PC が速くても遅くても、扉の開閉速度や敵の動きは常に同じ。オリジナル DOOM の 35Hz を厳密に守っています。

第5章

WADを読み解く

担当:wad/ フォルダ。生のバイト列を、意味のあるデータへ翻訳する“考古学”の層です。

まず wad-file.ts が入れ物を開けます。WAD は12バイトのヘッダ(識別子 IWAD/PWAD+ランプ数+目次の位置)に続いて、16バイトずつの目次(位置・サイズ・8文字の名前)が並ぶだけの素朴な構造。ここから名前でランプを引ける辞書を作ります。

flowchart LR
    RAW["生バイト列"] --> WF["wad-file
ヘッダ+目次"] WF --> MAP["map
頂点/線/区画"] WF --> PAL["palette
256色+34段"] WF --> GFX["graphics
パッチ/フラット/合成"] MAP --> BQ["bsp-query
点→区画"]

map.ts は地図データを固定長レコードとして読みます。E1M1 という目印ランプの直後に、決まった順で並ぶ8種類のデータを、それぞれ正確なバイト数で切り出します。

ランプ1件中身
VERTEXES4B頂点の座標 (x, y)
LINEDEFS14B壁の線(始点・終点・特殊番号・表裏の面)
SIDEDEFS30B面に貼る上・中・下テクスチャと所属セクター
SECTORS26B床/天井の高さ・テクスチャ・明るさ・タグ
SEGS / SSECTORS / NODES12/4/28BBSPの線分・区画・分割ノード
THINGS10Bモンスター・アイテム等の配置(種類・角度)

palette.ts は色の要。PLAYPAL(14種×256色×3バイト=10,752バイト)と COLORMAP(34段×256バイト=8,704バイト)を読み、両者を焼き合わせて 256×34 のルックアップ表テクスチャを作ります。これが次章の“本物の光”の材料です。graphics.ts は、列単位で透明を表現する DOOM 独特のパッチ形式や、64×64 のフラット、複数パッチを合成する TEXTURE1/2 を解読します。

最後に bsp-query.ts(43行)。「座標 (x, y) はどのセクターにいて、そこの床/天井の高さは?」を、BSP の木を根からたどって即答します。カメラ・モンスター・仕掛けが共通で使う、地図の“住所案内”です。

第6章

2Dの地図を3Dの壁に

担当:geometry/。DOOM の地図は本来“平面図”。それを立体の壁・床・天井に立ち上げます。

主役は build-level-geometry.ts(360行)。すべての壁の線(リニデフ)をたどり、その両脇のサイドデフから壁の四角形を起こします。座標は ワールド=(doomX, 高さ, doomY) で、DOOM の地図単位をそのまま1:1でワールド単位に使います(縮尺なし)。床と天井(フラット)は 64単位ごとにタイル貼り。

要素作り方
一枚壁(片側のみ)中テクスチャを床→天井まで一枚張り
段差(両側)床の高さが違えば下部、天井が違えば上部テクスチャを張る
床・天井BSPで各区画の凸多角形を復元し扇状に三角形化
空の天井F_SKY1 の天井は張らず、背景の空を透かす

床・天井の形は bsp.ts が復元します。地図全体を囲む大きな四角形を、BSP の分割線で次々に切り落としていくと、各区画のぴったりの多角形が残る——という賢い手法(Sutherland-Hodgman クリッピング)です。

🎨 DOOM の“うそ”の陰影

オリジナル DOOM は、東西に伸びる壁を少し暗く、南北の壁を少し明るく描きます(±16)。実際の光源計算ではなく、平坦な迷宮に立体感を与えるための意図的なごまかし(fake contrast)。このデモも忠実に再現しています。各頂点の色に「そのセクターの明るさ」を仕込んで、次章のシェーダへ渡します。

そして扉やリフトのように動く床・天井は、静的な壁とは別に dynamic-geometry.ts が担当。仕掛けが「動いた」と知らせるたび、動く部分の面だけを作り直します(マテリアルは使い回し、GPUのメッシュだけ再生成)。

第7章

本物の光を再現する

担当:doom-material.ts。このデモが最もこだわった、「DOOM にしか見えない画面」の正体です。

ふつうの 3D は色を RGB で持ち、距離に応じて滑らかに暗くします。でも DOOM は違いました。テクスチャは「色番号」だけ(R チャンネルにパレット番号、A に不透明度)を持ち、明るさは COLORMAP という34段の変換表で「番号 → 別の番号」に置き換えて表現します。だから DOOM の陰影は、滑らかではなくカクッと帯状に落ちるのです。

// パレット番号を、明るさの段(row)ごとに引き直す
// 明るいセクターほど浅い段。距離で段が深くなる。
baseRow = clamp(31 - floor(sectorLight / 8), 0, 31);
lightRow = clamp(baseRow + depth / 224.0, 0, 31);
// 224 = 1段ぶん暗くなるまでの距離(DOOM単位)

この DIST_PER_BAND = 224 が、あの「遠くが段階的に闇に沈む」距離感の数値です。シェーダは 256×34 のルックアップ表を、横=色番号・縦=明るさの段として引きます。色番号そのものは決して混ぜず(混ぜると存在しない色が生まれてしまう)、表を引いた後の最終 RGB だけを補間します。

🔍 ギザギザとチラつきの両立

近くの壁は 2×2 のバイリニアで軽く滑らかに、斜めに見た遠くの壁は最大16回のサンプリングを足し込んで、DOOM 名物の縦縞のチラつきを抑えます。「ドット感は残しつつ、目に痛いエイリアスは消す」——レトロ再現とモダンな品質の、絶妙な両立です。

第8章

空のからくり

担当:sky.ts(69行)。DOOM の空は「無限に遠い背景」。その錯覚を、たった1個の球で作ります。

仕掛けはこうです。カメラを中心に置いた直径 2000 の球を用意し、そのピクセルを強制的に最遠面へ(深度を反転Zの奥へ)押し込みます。すると空は必ず「すべての壁より後ろ」に描かれ、天井を張らなかった穴からだけ覗く。描画順を気にせず、空が確実に背景を埋めます。テクスチャは視線の方向から貼り、DOOM 流に360°で4回くり返します。空は距離や明るさで暗くならず、常に一番明るい段(row 0)で描かれます。

第9章

モンスターの設計図

担当:mobj/ フォルダ。DOOM の敵・弾・アイテムを支える、有名なデータ駆動アクターシステムの移植です。

あらゆる“動くもの”は mobj(マップオブジェクト)という共通の器。位置・体力・フラグ・状態を持ちます。その設計は3段構え——インフォ(型)→ ステート(アニメと行動のコマ)→ アクション(AIの関数)。この3つの表を think.ts が 35Hz で1 tic ずつ進めます。

flowchart LR
    INFO["info
型(体力/速さ/半径)"] --> STATE["states
コマ{絵,フレーム,tics,行動,次}"] STATE --> ACT["actions
AI関数(A_Look等)"] ACT --> THINK["think
1ticずつ進める"] THINK --> WORLD["world
全mobjの管理"]

info.ts の目録には、モンスター・アイテム・武器・弾・置物までがずらり。E1M1 に登場する主なモンスターはこちらです(数値はソース実測)。

モンスター体力速さ攻撃
ゾンビマン(POSS)208ヒットスキャン(拳銃)
シャットガンガイ(SPOS)308ヒットスキャン(散弾)
インプ(TROO)608近接+火球(弾)
デーモン/スペクター(SARG)15010近接のみ(噛みつき)
カコデーモン(HEAD)4008浮遊+火球
バロン(BOSS)10008火球
ロストソウル(SKUL)1008浮遊・自発光
🔢 固定小数点は使わない

オリジナル DOOM は整数の固定小数点(FRACUNIT)で全計算していましたが、この移植はふつうの浮動小数点で、DOOM の地図単位をそのまま使います。読みやすさを優先した、現代的な割り切りです。

第10章

敵を動かす頭脳

担当:actions.ts。ステートの各コマに紐づく“行動”が、敵の思考そのものです。

DOOM の AI は驚くほどシンプルな関数の集まりです。ステートが進むたびに、そのコマに書かれた行動名が呼ばれます。

行動中身
A_Lookプレイヤーが視界に入れば標的に設定し、覚醒(見え音を鳴らす)
A_Chase標的へ接近。近ければ近接、条件が揃えば遠隔攻撃へ。8方向で移動
A_FaceTarget標的の方を向く
A_*Attack各モンスター固有の攻撃(拳銃/散弾/火球/噛みつき)
A_Pain / A_Scream / A_Fall被弾のうめき/断末魔/死んで当たり判定を消す

攻撃するかどうかの判断(checkMissileRange)も DOOM 譲り。距離が近いほど発砲しやすく、遠いと撃ち控える確率計算になっています。近接の間合いは MELEE_RANGE = 64、遠隔の射程は MISSILE_RANGE = 2048(=32×64)。移動方向は「標的に近づく向き」を対角優先で選び、壁や仲間にぶつかれば別の向きを試します。

第11章

スプライトを板に描く

担当:sprites.tssprite-render.ts。DOOM の敵は3Dモデルではなく、1枚絵の板です。

モンスターは常にカメラへ正面を向くビルボード(板)に描かれます。でも、ただ正面を向くだけでは“書き割り”になってしまう。そこで DOOM は8方向ぶんの絵を用意し、「プレイヤーがどの角度から敵を見ているか」に応じて絵を差し替えます。横を向いた敵は横向きの絵、背を向けた敵は後ろ姿の絵、という具合です。

その角度計算が BAM(角度を32bit整数で表す方法)の見せ場。「視線→敵の方向」と「敵の向き」の差をビットシフトするだけで、8方向のどれかへ即座に振り分けられます。絵はスプライト名+フレーム文字+方向番号(例 TROOA1)で管理され、左右対称の向きは1枚を反転して使い回します。全スプライトは1枚の大きなアトラス(1024幅)に詰め込まれ、壁と同じ COLORMAP の陰影で距離に応じて暗くなります。

第12章

プレイヤーと武器

担当:player.tsweapon-view.ts。体力・防具・弾薬・所持武器、そして手元の銃の描画です。

8種の武器はそれぞれ、弾の種類・連射間隔(tic)・発砲音を持ちます。開始時は拳とピストル、体力100、弾薬は弾丸50発から。

武器連射(tic)ダメージ(1発)
拳 / チェーンソー12 / 42〜20(近接64)
ピストル弾丸125 / 10 / 15(散り±0.04)
ショットガンシェル287発の散弾×5/10/15
チェーンガン弾丸45 / 10 / 15
ロケット / プラズマ / BFGロケット/セル18 / 3 / 4010〜50

手元の武器は weapon-view.ts が仮想 320×200 の画面に 2D で重ねます。移動中は上下左右に揺れ(横は cos、縦は sin の絶対値で“8の字”)、発砲した瞬間は発射コマ+別レイヤーのマズルフラッシュ0.12 秒だけ重ねる。すべて COLORMAP の一番明るい段で、常にくっきり描かれます。

第13章

撃つ・当たる

担当:combat/attack.tsphysics/collision.ts。弾の当たり判定と、壁ずりの移動です。

ほとんどの武器はヒットスキャン——撃った瞬間に光線を飛ばし、最初にぶつかる壁までの距離を測り、その手前にいる敵を探して当てます。命中すれば血(BLOOD)、外れれば煙(PUFF)を出し、damageMobj が体力を削る。体力が尽きればモンスターは死亡ステートへ、被弾すれば painChance の確率でひるみステートへ遷移します。インプの火球だけは本物の飛翔体として飛び、着弾で爆発します。

移動と当たり判定は collision.ts。プレイヤーは半径16の円(高さ56、視点高41、登れる段差24)としてモデル化され、壁の線に沿って滑ります(法線方向に押し戻して接線方向の動きは残す=ウォールスライド)。両側が通れる壁は「すき間が身長より狭い/段差が24を超える」ときだけ塞がる。扉やリフトで高さが変わると、この判定もその場の高さで更新されるので、閉じる扉に挟まれます。

第14章

扉とリフト

担当:specials.ts(410行・最大のファイル)と special-types.ts。壁や床に仕込まれた“仕掛け”です。

DOOM の扉・スイッチ・リフトは、リニデフに割り当てられた番号で表されます。special-types.ts はその番号表(E1M1 が使う範囲)。「どう起動するか(押す/歩いて横切る/スイッチ)」「くり返せるか」「何をするか」を定義します。

番号起動動作速度/待機
1使う手動ドア(開いて待って閉じる)2 / 150
2横切るドア開けっ放し2 / —
117使う高速ドア(ブレイズ)8 / 150
62 / 88スイッチ/横切るリフト(下げて待って戻す)4 / 105
23スイッチ床を最低の隣接床まで下げる2 / —
11スイッチレベル出口

specials.ts はこれを実際の“動く床・天井”に変えます。Space で使うと、正面へ 64 の光線を飛ばして手前のスイッチ/ドアを起動。歩いて線を横切れば、横断型の仕掛けが発火。ドアは「隣接する一番低い天井の4つ下」まで開き、150 tic 待って閉じます。

🚪 挟まれても潰されない

閉じかけのドアの真下にプレイヤーがいて、頭上の余裕が 56(身長)を切りそうなら、ドアは潰さずに再び開きます。オリジナルの“親切設計”まで再現。動いた区画は「汚れフラグ」を立て、第6章の動的ジオメトリが該当部分だけ作り直します。

第15章

ステータスバー

担当:hud.ts(342行)。画面下のあの茶色いバーを、WAD の本物のグラフィックから組み立てます。

体力・防具・弾薬・武器スロット・鍵——すべて WAD の STBAR 系グラフィックを1枚のアトラスに焼き、仮想 320×200 の座標(バーの上端 y=168)に、当時のレイアウト定数どおりに並べます。数字も本物のフォント絵です。

😀 表情が変わる“あの顔”

中央の DOOMガイの顔も再現。体力から痛みレベル(0〜4)を出し、被弾直後は「イテッ」という顔、死ねば骸骨、平常時は 0.5 秒ごとに左・正面・右へ視線を動かします。DOOM に無かった十字カーソルだけは、遊びやすさのために作者が足したもの(DOM オーバーレイ)です。

第16章

担当:sound.ts(86行)。効果音は合成ではなく、WAD の中の本物のサウンドを鳴らします。

DOOM の効果音は DS で始まるランプ(例:DSPISTOL)に、DMX 形式の 8bit PCM として入っています。sound.ts はこれを解読し(サンプルレートは通常 11025Hz、前後16サンプルの余白は切り落とす)、Web Audio の AudioBuffer に変換して再生。同じ音の連発は 1 tic(1/35秒)に1回まで、音量は 0.6 に抑えます。ブラウザの制約で、音は最初のキー操作の後から鳴り始めます。

第17章

設計テーマ

29ファイルに散らばって見えて、じつは一貫した4つの考え方が通っています。

⚖️ クリーンルームで作る

GPLのDOOMソースは見ない・写さない。公開仕様だけを頼りにゼロから実装し、データも自由な Freedoom を使う。だから堂々と公開・教材化できる。

📊 データ駆動で動かす

モンスターも仕掛けも、ロジックではなくで定義。インフォ→ステート→アクション、線番号→動作。表を足すだけで敵や仕掛けが増える。

💡 忠実さは“らしさ”に宿る

1:1のスケール、±16のfake contrast、224単位ごとの帯状の闇、パレット番号を混ぜない描画。細部の再現が「DOOMにしか見えない画面」を作る。

⏱️ 描画と進行を分ける

見た目は可変フレーム、ゲームは35Hz固定tic。この分離が、PCの速さに左右されない“当時のままの手ざわり”を保証する。

📝 コメントは「理由の記録」

このコードのコメントには「なぜそうしたか」と「どの公開資料に基づくか」がていねいに書かれています。GPLソース不参照の宣言/閉じるドアが潰さず反転する理由/巨大な床を影から外す判断——判断の理由ごと読めるのが、このサンプルの教材価値です。Minecraft・Platformer・Tetris・Sandblox デモと共通する“コメント文化”が、ここにも息づいています。

第18章

ファイル一覧(全29ファイル)

コードリーディングのおともに。行数は master ブランチのソース実測値です。specials.ts が最大で、合計およそ5,010行。

ファイル行数やくわり
エントリ・司令塔
doom.ts49エンジン起動・WAD取得・レベル構築の呼び出し・ループ開始
doom-level.ts309レベル全体を組み立て、35Hz固定ticの更新ループとカメラを回す
WAD解析
wad/map.ts219地図ランプ(頂点/線/面/区画/BSP/配置)を固定長で解析
wad/graphics.ts192パッチ/フラット/PNAMES/合成テクスチャの解読
wad/wad-file.ts100WADの入れ物(ヘッダ+目次)を開き、ランプを引く
wad/palette.ts75PLAYPAL/COLORMAPを256×34のルックアップ表テクスチャに
wad/bsp-query.ts43点→区画・床/天井高さをBSPで即答(住所案内)
ジオメトリ
geometry/build-level-geometry.ts3602D地図→3Dの壁/床/天井をテクスチャ別に生成(fake contrast)
geometry/bsp.ts107BSP分割面で各区画の凸多角形(床天井の形)を復元
geometry/dynamic-geometry.ts84扉・リフト等の動く面だけを再生成
レンダリング
render/sprites.ts291スプライトを解読しアトラス化、8方向から正しい絵を選ぶ
render/weapon-view.ts224一人称の武器を2Dで重ね、揺れとマズルフラッシュ
render/doom-material.ts159パレット+COLORMAPの帯状陰影を再現するWGSLマテリアル
render/sprite-render.ts107全mobjをカメラ正面のビルボードとして描画
render/sky.ts69F_SKY1の空。反転Zの最遠面に押し込む球
render/texture-cache.ts69壁/床テクスチャを必要時にGPUテクスチャへ変換・キャッシュ
アクター(mobj)
mobj/info.ts219全アクターの型目録(体力/速さ/半径/フラグ/音)
mobj/actions.ts201AI・攻撃の行動関数(A_Look/A_Chase/各攻撃)
mobj/world.ts199THINGSからmobjを生成、毎tic進行・取得・ビルボード列を作る
mobj/states.ts177ステート表(絵/フレーム/tics/行動/次)と各mobjの入口
mobj/think.ts1261ticの進行・移動・重力・モンスターの歩行
mobj/mobj.ts67Mobj構造体と8方向の向き定義
プレイヤー・戦闘・物理
player/player.ts269体力/防具/弾薬/武器の状態と、選択・発砲・被弾・取得
combat/attack.ts211視線判定・ヒットスキャン・飛翔体・ダメージと状態遷移
physics/collision.ts181円vs線の移動・壁ずり・段差・mobj同士の押し合い
仕掛け・UI・音
specials/specials.ts410ドア/リフト/床/スイッチ/出口の実行時ロジック
hud/hud.ts342本物のSTBARグラフィックでステータスバー+表情の顔
sound/sound.ts86WADのDMX音(DS*)をWeb Audioで再生
specials/special-types.ts65リニデフ特殊番号の表(速度/待機/起動方法)

行数は master ブランチ(2026年時点)のソース実測値です。合計およそ5,010行(29ファイル)。