When I was younger, two of my very favorite games were DOOM and DOOM 2.

In 1997 id Software published the source, which is nowadays available on GitHub.

To get one of the games running, either DOOM 1 or DOOM 2, you need the file doom.wad or doom2.wad.

With documents like THE UNOFFICIAL DOOM SPECS, it is easy to understand their structure.

In this article I want to show, how you can implement a simple and nice map viewer with Next.js and Tailwind CSS, because especially Next.js is the framework we at e.GO Mobile using for most of our web applications.

Requirements

Beside a current version of Node.js, you also require the original WAD files doom.wad and/or doom2.wad.

You have to copy them into wads/ subfolder.

Create Next.js project

Execute

npx create-next-app@latest

in your terminal. I decided to select the following options:

  • What is your project named?: tgf-doom-mapviewer
  • Would you like to use TypeScript?: Yes
  • Would you like to use ESLint?: Yes
  • Tailwind CSS?: Yes
  • Would you like to use App Router? (recommended): No
  • Would you like to customize the default import alias (@/*)?: No

Custom HTTP server

For the demo, I created a server.js with a custom HTTP handling:

const {
    parse
} = require('node:url');
const {
    createServer
} = require('@egomobile/http-server');
const next = require('next');

const dev = process.env.NODE_ENV?.toLowerCase().trim() === "development";
const hostname = '0.0.0.0';
const port = 3000;

async function main() {
    const app = next({ dev, hostname, port });
    await app.prepare();

    const handle = app.getRequestHandler();

    const server = createServer();

    const middlewares = [];

    // any method ...
    server.all(
        () => true, // ... and any path
        middlewares,
        async (request, response) => {
            request.appRoot = __dirname;

            await handle(request, response, parse(request.url, true));
        },
    );

    await server.listen(port);
    console.info(`ℹī¸ Next.js instance now running on port ${port} ...`);
}

main().catch((ex) => {
    console.error('đŸ”Ĩ [UNHANDLED EXCEPTION]', ex);

    process.exit(1);
});

This gives me more flexibility and lets me enhance the Next.js request with appRoot directory, so I am able to find the .wad files much easier inside the API endpoint.

Additionally I had to update the dev and start scripts in package.json as well.

SASS

SASS is a preprocessor scripting language that is used to generate CSS code for web development. It provides a set of features and functionalities that extend the capabilities of CSS, making it easier and more efficient to write and maintain stylesheets for web applications.

SASS allows web developers to use variables, nested rules, mixins, and other programming constructs that are not available in CSS. This makes it possible to write more reusable and modular code, which can be easier to maintain and update over time. SASS also provides a range of built-in functions and operators that can be used to manipulate colors, fonts, and other style properties, further simplifying the development process.

One of the main benefits of using SASS is that it can significantly reduce the amount of code that needs to be written. Since SASS is a preprocessor, it allows developers to write more concise and expressive code, which is then translated into standard CSS by the SASS compiler. This can result in faster load times and improved performance for web applications.

I addtionally added sass as a module dependency in my package.json, which is automatically handled by Next.js, when renaming .css files to .scss.

Loading WAD files

I only focused on 2 kind of data:

  • LINEDEFS: each entry represents a line from one of the point (VERTEXES) to another
  • THINGS: in DOOM e.g. each entry represents “thing” like player start position, monster, weapon, key, barrel, etc.

To load the data in the frontend, I created the both GET endpoints /api/linedefs and /api/things in the backend part of Next.js.

Displaying maps

While on the one hand, I am using Tailwind CSS for the UI as set uped by create-next-app, I am on the other hand making use of a HTML canvas for the more complex low-level stuff.

The page component can be found in index.tsx file.

Start the project

After you copied at least one of the IWAD files (doom.wad or doom2.wad) to wads/ subfolder, you can start the application locally with

npm run dev

and open it with http://localhost:3000/ in a modern browser.

Conclusion

Even though DOOM is over 30 years old, it is still enjoyable to play. The unofficial specs documentation explains all the essential aspects of a WAD file.

Therefore, enhancing this demo project to enable the creation of Patch WAD (PWAD) files from existing levels, with a different list of things such as monsters, weapons, start points, etc., should not be a big deal.

Have fun while trying it out! 🎉