Open-source project
ad044/lainTSX avatar
ad044/lainTSX

lainTSX: a browser port of Serial Experiments Lain with a multi-language subtitle layer

WebGL implementation of the Serial Experiments Lain PSX game

711 stars42 forksTypeScriptLicense varies

At a glance

What is it?
lainTSX re-implements the PlayStation game Serial Experiments Lain in the browser on top of three.js, and its real contribution is a subtitle system built to carry several languages at once, aimed at players who were previously forced to read a translation while playing. It suits a player with the original discs who wants to read the game in their own language, and it is a fan project that ships no game assets of its own.
Who is it for?
lainTSX fits a player who owns the original PlayStation discs, cannot read Japanese, and wants the game running in a browser with subtitles they can switch between languages, and it does not fit anyone looking for a legal substitute for owning the game, because the repository deliberately hosts no game assets and requires the original binaries to be supplied by the user.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 73 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why the port exists, and it is not about the graphics

lainTSX is a browser-based implementation of the Serial Experiments Lain PSX game using three.js with the aim to provide multi-language support and make it more accessible.

The history section of the README explains the motivation, and it is a translation problem rather than a technical one. The original PSX game was released in Japan in 1998 and never got a proper English adaptation, which resulted in all non-Japanese speaking players either having to play through the game while simultaneously reading through the translation, or simply not playing the game at all and only reading it.

That is a specific and unusually well described problem, and it explains why the project exists in this shape. A faithful emulation of the original would reproduce the original problem exactly, so a port that does not fix the language issue would be pointless. The goal of this project is to provide a better experience for those willing to play the game, and the way to do so is by implementing a subtitle system with the capability to support multiple languages.

So the subtitle layer is the product here. The three.js renderer is the vehicle. That is worth keeping in mind when reading the rest of the repository, because the parts that get the most attention in a game port, the renderer fidelity and the frame timing, are exactly the parts this project is not about.

The repository is TypeScript with a package version of 0.4.4, marked as private, and the default branch is master. The last push was on 2026-08-11 and the repository has no GitHub releases, so the commit history is the only record of what changed and when.

A build toolchain that treats game data as a first class input

The package.json shows a front end build with a very specific shape, and the dev dependencies explain the pipeline.

The three scripts are the standard Vite set, with a TypeScript compile step in front of the production build.

json
        "dev": "vite",
        "build": "tsc && vite build",
        "preview": "vite preview"

The dev dependencies are where the project reveals itself. There is a single runtime dependency, three at version 0.162.0, which is the renderer. Everything else is tooling for turning PlayStation data into browser assets.

kaitai-struct is a library for working with binary format descriptions, and its presence tells you the extraction pipeline treats the disc images as structured binary rather than as opaque blobs. sharp and pngjs handle image conversion. maxrects-packer is a rectangle packing library, which is how texture atlases get assembled, since a PSX texture set arrives as a set of separate images that want to be one WebGL texture. vite-plugin-gltf and vite-plugin-glsl handle the glTF models and the shader code, which is the standard three.js asset pipeline. vite-plugin-static-copy places the extracted game files into the build output.

The rest are ordinary but telling. yargs is the command line parser for the extraction script, command-exists checks that a required external program is present before running, and typescript at 5.2.2 with vite at 5.1.4 are the current toolchain for the project.

The two plugins for glTF and GLSL are the reason the project is a port rather than a demo. A PlayStation game is a set of models, textures, audio and code, and each of those has a browser equivalent, but the conversion is not free, and doing it with plugins rather than by hand is what keeps the pipeline repeatable when the extraction script changes.

The extraction script, and why you need your own disc images

The building section is the part of the README that will surprise anyone expecting a clone-and-run project, and it is worth reading carefully.

Since the repository doesn't host any of the game's assets, you need to provide the original binaries yourself. By using a script, the assets necessary are extracted and formatted from the provided binaries. The dependencies for running the script are Java, FFmpeg, and ImageMagick at version 7 or above.

The instructions are specific. Inside the scripts folder, create a discs folder and put both disc binaries there under the names disc1.bin and disc2.bin. Then run extract.mjs, which also has potential flags you may want to use such as --no-delete and --tempdir.

So the workflow is: supply your own disc images, run a Node script that calls out to Java, FFmpeg and ImageMagick, and it produces the assets the browser build needs. The reason for the external toolchain is the media formats. A PSX disc carries video in a form that has to be decoded and re-encoded, audio that has to be converted, and textures that have to be repacked, and each of those has a mature command line tool that does it better than a hand-written parser would.

There is a stated limitation: currently the extraction script doesn't extract SFX, but the game still runs fine locally. So the build produces a working game with missing sound effects, which is the kind of trade a port makes when the audio format work is still in progress.

The TODO list names the two open items plainly. The first is to finish writing the extraction script, and the second is to improve or complete the translation. Both are still listed as unfinished, which is the honest state of the project and also the main reason a first run is a developer task rather than an end user task.

Translations on Crowdin, and the subtitle system underneath

The contribution model for the text is the part of this project that is most likely to produce a result for a player, and it is a familiar one.

The README points contributors to a Crowdin project for the translations, and the screenshots directory holds eight captures of the running game. The Crowdin arrangement means translation happens in a tool built for it rather than in pull requests against source files, which lowers the barrier for a contributor who wants to fix a line of dialogue in a language they speak and does not want to learn the asset pipeline.

The subtitle system is the reason Crowdin output matters. The stated aim is multi-language support, and the history section makes clear that the game's defining accessibility problem was reading a translation while playing. A subtitle layer that carries several languages at once does two things at once: it lets a player read the game in their own language, and it lets them compare, since a second language is present rather than substituted.

That is the design decision that makes the project worth reading even by someone who will never play it. A faithful port reproduces the original experience. This one treats the original's Japanese-only presentation as a defect to be engineered away, and it does so by moving the text out of the game's own assets and into a layer the port controls.

The other end of the project is the code and asset contribution. The README asks for ideas, suggestions, bug reports, and help with the translation or anything else, all through the issue tracker. The tools used during development are named, and the first is the one that explains the whole extraction approach: jPSXdec, described as a PlayStation 1 audio and video converter, with three.js listed as the JavaScript 3D renderer.

A multi-page static site rather than a single page game

The repository layout tells you something the README does not. There is no single index that does everything, and the top level holds four HTML entry points alongside the source: index.html, game.html, guide.html and notes.html, plus a public directory, a scripts directory, src, a screenshots directory, a vite.config.js and a tsconfig.json. There is also a .gitmodules file and a .prettierrc.

Four pages means four roles. The game itself needs a page of its own, separate from the surrounding site, and a guide page and a notes page sit alongside it as documentation and commentary. The index is the entry point that ties them together. Splitting the game into its own page is the practical choice for a WebGL application, since the canvas and its render loop want a page that does not also carry the weight of a documentation site.

The .gitmodules file indicates that at least part of the toolchain is a git submodule, which in a project like this is the likely home for jPSXdec, the PlayStation 1 audio and video converter, since it is listed among the tools used during development. Pulling it in as a submodule rather than vendoring it keeps the build reproducible and keeps the dependency's own licence and provenance intact, which matters for a project that has to be careful about what it includes.

The gitignore entry, the prettier configuration and the presence of package-lock.json alongside a private package marked with type module all point at a conventional modern JavaScript front end project. The package is private, which fits a game project that is not published to a registry, and the module type setting means the tooling and the extraction script are ES modules, which is also why the extraction script is named extract.mjs.

The vite-plugin-static-copy dependency is the piece that connects the two halves. The extracted assets have to end up in the built site, and that plugin is what moves them from the extraction output into the directory the browser loads.

What this is, and what it deliberately is not

It is worth being direct about what this repository is, because the name invites a misreading.

It is not an emulator and not a copy of the game. The README says the repository doesn't host any of the game's assets, and the user supplies the original disc binaries. The renderer is a reimplementation on three.js, so the code that draws the game is new, and the content is the user's own copy.

That structure is a deliberate legal choice with a practical consequence. The project can be published and studied because it distributes no copyrighted game content, and the person running it is the person who owns the discs. The cost is that nobody can install this without already owning the game, and the extraction step is a per-user task rather than a download.

The realistic alternative for someone who wants to play this game today is to look for a version that already ships the assets and a finished translation. A port like this one is a better answer for a player who specifically wants the multi-language subtitle system, or for a developer who wants to see how a PlayStation title is reimplemented on a modern renderer.

The other honest point is the maturity. The TODO list has two items, both unfinished, and one of them is the extraction script that every user has to run. The version is 0.4.4 and the last push was on 2026-08-11, so the project is being worked on, but it is early enough that the README is thin on every topic a user would ask about: it does not document the browser requirements, does not list the supported browsers, does not describe the subtitle controls, and does not explain how the language switching works at runtime. The wiki is not mentioned, and there is no separate documentation site, so the answer to most questions about using the port is to read the source.

The licence is recorded as unknown for the repository, so anyone planning to redistribute a build or reuse the subtitle pipeline commercially needs to establish the terms first.

Editorial conclusion

lainTSX fits a player who owns the original PlayStation discs, cannot read Japanese, and wants the game running in a browser with subtitles they can switch between languages, and it does not fit anyone looking for a legal substitute for owning the game, because the repository deliberately hosts no game assets and requires the original binaries to be supplied by the user. Before building it, expect to run the extraction script over your own disc images yourself, since the README is explicit that the repository hosts none of the game's assets, and note the state of the two open tasks, which are that the extraction script is unfinished and the translation is incomplete, so a first run is closer to a developer task than a user task.

Frequently asked questions

How do I build lainTSX locally?

The repository hosts none of the game's assets, so you supply the original disc binaries yourself, placing them in a discs folder inside the scripts folder as disc1.bin and disc2.bin, then run extract.mjs. That script needs Java, FFmpeg and ImageMagick 7 or above, and the browser build is served with the dev script, which runs vite.

Does lainTSX include the game's graphics and audio?

No. The README states that the repository doesn't host any of the game's assets and that you need to provide the original binaries yourself. The extraction script produces the assets from those binaries, and it is noted that the script currently doesn't extract SFX, though the game still runs fine locally.

How do I help translate lainTSX?

Translations are managed through a Crowdin project, and the README points contributors there. The TODO list still includes improve or complete the translation as an open item, alongside finishing the extraction script.

Official sources

  1. ad044/lainTSX on GitHub
  2. Issues
  3. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ad044-laintsx.svg)](https://hysenlabs.com/projects/ad044-laintsx)

Was this useful?