Courage begins by trusting oneself
GameOptions are engine-level toggles that instantly apply changes when switched. They're also present in .ini configuration files within the engine directory. With every major patch, some options are added, removed, or modified. Not all of them have a noticeable effect — or work at all. It’s trial and error. 😉
Personally, I refer to each option by its PATH, but in-game and in .ini files, the final part needs to be split into two: what I call GROUP and OPTION.
To use these options in-game, you’ll need Cyber Engine Tweaks. Each data type requires a different command — the most common types are INT, BOOL, and FLOAT.
As an example, let’s use the path: RayTracing/Diffuse/UseScreenSpaceData. This is a boolean option — it can only be set to true or false.
GameOptions.SetBool('RayTracing/Diffuse', 'UseScreenSpaceData', true)
To make your options persistent, you’ll need to write them to an .ini file. Cyberpunk reads these at startup and applies the values automatically. The typical location for these files is: <INSTALL DIR>\engine\config\platform\pc
[RayTracing/Diffuse]
UseScreenSpaceData = true
The full list includes 1500+ entries, so I’ve moved it to /gameoptions (not optimized for mobile). Includes version-specific filtering and search support!
Sometimes I like to play older versions of Cyberpunk, especially 1.31, because the rendering engine changed significantly between versions 1.2 and 1.5+. I wasn’t able to download anything earlier than 1.31 via GOG, so I focused my efforts on Steam.
To get older Cyberpunk versions, I used the DepotDownloader from GitHub, which is built on .NET by Microsoft. All you need is the AppID, the DepotID, and the Manifest. A great resource for that is SteamDB - the Manifest determines which version from the app's depot you’ll download.
Open a terminal, navigate to the unpacked DepotDownloader folder, and run:
DepotDownloader.exe -app 1091500 -depot 1091501 -manifest <Manifest> -username <Username> -password <Password>
If you’ve got Steam Guard enabled, you’ll likely receive an authentication code via email. DepotDownloader will prompt you to enter it.
Below are the major versions with their final patch.
Version | Manifest | Patch | Manifest | ||
---|---|---|---|---|---|
1.0 | 7287387370544759862 | 7 December 2020 | 1.06 | 583937837845971710 | 23 December 2020 |
1.1 | 3852482208634779141 | 22 January 2021 | 1.12 | 6404500526474240765 | 5 February 2021 |
1.2 | 912635795014659773 | 29 March 2021 | 1.23 | 5662812629377532750 | 17 June 2021 |
1.3 | 4226367547239603660 | 18 August 2021 | 1.31 | 3225568184502668130 | 14 September 2021 |
1.5 | 4596392258055187917 | 15 February 2022 | 1.52 | 5869743417560122937 | 5 April 2022 |
1.6 | 9024153387735370035 | 6 September 2022 | 1.63 | 6594873489665865240 | 23 June 2023 |
2.0 | 1799993379545736809 | 21 September 2023 | 2.02 | 4882158097132343077 | 26 October 2023 |
2.1 | 2238892413801664242 | 5 December 2023 | 2.13 | 4350623720177810551 | 12 September 2024 |
2.2 | 6971552143247463690 | 10 December 2024 | 2.21 | 8420445566849588826 | 23 January 2025 |
Patch 1.31 / CET 1.16.4
The last update with Static Resolution Scaling (SRS), which allowed overriding up to 200% and beyond. At double resolution, the rendered image appeared noticeably smoother – ideal for high-quality screenshots, as anti-aliasing had more pixels to work with.
Patch 1.61 (DLSS) / CET 1.22.0
Introduced DLSS 3 support in Cyberpunk.
CET 1.16.4
Upgraded ImGui to 1.84.2, resolving issues with BeginDisabled() and EndDisabled()
CET 1.18.0
First version to support symbolic links in the filesystem. Also added the Lua function ModArchiveExists("example.archive")
CET 1.20.0
Transitioned to OpenResty LuaJIT
CET 1.21.0
Upgraded to ImGui 1.88 (with docking support) and adopted Noto Sans as the default font. Introduced scalable UI. The window arrow was removed in this version but brought back in the next.
CET 1.31.3
Disabled console logging for changes to game options.
ImGui styling is a kind of art in itself — but it’s not all that difficult. If you want a unique UI, you’ll need to work with color definitions, padding, and line flow. ImGui renders elements line by line, combining the padding from both the element and its window, so there are certain layout limitations — it’s not directly comparable to HTML + CSS.
My approach is a little complex, but it results in precise positioning across all resolutions. CET’s built-in scaling works surprisingly well and can be a big help if you don’t want to go full manual.
The reference documentation can be found in the CET GitHub repo. It lists all commands, though not very extensively.
Examples below are taken from CharLi, my playground for advanced ImGui styling.
There are four main commands for styling and coloring elements. These are stack-based, so make sure to pop what you push — otherwise you’ll override other mods or even CET’s own windows. Failure to do so can lead to glitches or crashes.
Color definitions:
ImGui.PushStyleColor(<PART OF ELEMENT>, <COLOR>)
ImGui.PopStyleColor(<NUMBER OF COLOR DEFINITIONS>)
Style variables (like padding or alignment):
ImGui.PushStyleVar(<PART OF ELEMENT>, <VALUE>, <OPTIONAL>)
ImGui.PopStyleVar(<NUMBER OF STYLE DEFINITIONS>)
Each element has its own styleable parts — too many to list here. To explore them all, check the ImGui source. Color enums begin here.
For example, FramePadding affects windows, tab bars, tabs, collapsing headers, and more. Here's a basic window using padding and custom flags:
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, 5, 7)
ImGui.Begin("Window Title", ImGuiWindowFlags.NoTitleBar + ImGuiWindowFlags.NoScrollbar + ImGuiWindowFlags.NoScrollWithMouse)
ImGui.End()
ImGui.PopStyleVar(1)
Styling colors works just like style vars. I like using 'ImGui.GetColorU32(r, g, b, a)' for RGBA colors. Values range from 0.0 to 1.0 for each channel.
The alpha channel controls transparency: 0.0 = fully transparent, 1.0 = fully opaque.
If your button is transparent and your window has its own background color, the button will inherit that look visually.
ImGui.PushStyleColor(ImGuiCol.WindowBg, ImGui.GetColorU32(1, 0, 0, 0.5))
ImGui.Begin("Name of the Window", ImGuiWindowFlags.NoTitleBar + ImGuiWindowFlags.NoScrollbar + ImGuiWindowFlags.NoScrollWithMouse)
ImGui.End()
ImGui.PopStyleColor(1)
Now you’ve got a semi-transparent red window — no title bar, just vibes 😎
CET comes with a built-in library of glyphs (icon characters). They can be used anywhere text is accepted: button labels, window titles, tooltips, etc.
Browse icons at Material Design Icons, but note: the names are slightly different in CET’s file \cyber_engine_tweaks\scripts\IconGlyphs\icons.lua. For example: clock-outline on the MDI site = ClockOutline in CET.
We’ll give our red ghost window an absurd glyph-based title:
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, 5, 7)
ImGui.PushStyleColor(ImGuiCol.WindowBg, ImGui.GetColorU32(1, 0, 0, 0.5))
ImGui.Begin(IconGlyphs.ClockOutline..IconGlyphs.AlphaS..IconGlyphs.AlphaA..IconGlyphs.AlphaL..IconGlyphs.AlphaA..IconGlyphs.AlphaD)
ImGui.End()
ImGui.PopStyleColor(1)
ImGui.PopStyleVar(1)
This is a sneaky trick that works surprisingly well. ImGui allows negative spacers using ImGui.Dummy(), which acts as offset padding.
If you know the dimensions of an element, you can "rewind" the layout and overlap another — useful for custom toggles or visual gimmicks.
For instance, in CharLi I use a fake slider overlaying a transparent button — so the button handles input, while the slider delivers the style.
Step 1: Transparent Button
ImGui.PushStyleColor(ImGuiCol.Button, ImGui.GetColorU32(0, 0, 0, 0))
ImGui.PushStyleColor(ImGuiCol.ButtonActive, ImGui.GetColorU32(0, 0, 0, 0))
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, ImGui.GetColorU32(0, 0, 0, 0))
ImGui.PushID("Unique_Button_Name")
ImGui.Button("", 32, 18)
ImGui.PopID()
ImGui.PopStyleColor(3)
Step 2: Rewind
ImGui.SameLine()
ImGui.Dummy(-32, 0)
ImGui.SameLine()
Step 3: Styled Slider Overlay
ImGui.PushStyleVar(ImGuiStyleVar.GrabRounding, 10)
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 10)
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, 0, 0)
ImGui.PushStyleVar(ImGuiStyleVar.FrameBorderSize, 2)
ImGui.PushStyleColor(ImGuiCol.Text, ImGui.GetColorU32(0, 0, 0, 0))
ImGui.PushStyleColor(ImGuiCol.Border, ImGui.GetColorU32(0.3, 0.3, 0.37, 0.7))
ImGui.PushStyleColor(ImGuiCol.FrameBg, ImGui.GetColorU32(0.2, 0.2, 0.27, 0.5))
ImGui.PushStyleColor(ImGuiCol.FrameBgActive, ImGui.GetColorU32(0.2, 0.2, 0.27, 0.5))
ImGui.PushStyleColor(ImGuiCol.FrameBgHovered, ImGui.GetColorU32(0.2, 0.2, 0.27, 0.5))
ImGui.PushStyleColor(ImGuiCol.SliderGrab, ImGui.GetColorU32(1, 0.56, 0.13, 0.85))
ImGui.PushStyleColor(ImGuiCol.SliderGrabActive, ImGui.GetColorU32(1, 0.56, 0.13, 0.7))
ImGui.SetNextItemWidth(32)
ImGui.PushID("Unique_Slider_Name")
ImGui.SliderInt("", value, 1, 0)
ImGui.PopID()
ImGui.PopStyleColor(7)
ImGui.PopStyleVar(4)
ImGui.SameLine()
ImGui.Text("The Real Title")
IMPORTEND: If a widget has no label (""), use PushID / PopID — otherwise, identical elements will share state and behave unpredictably.
And voilà — you’ve got a fully-styled, interactable FrankenWidget with decoupled input and visuals. Like dark UI necromancy in Lua 😄
This technique only works when you know the exact width of the elements and apply it on the same horizontal line. Vertical overlap between different rows isn’t possible — ImGui’s layout is strictly line-based.
to be continued...
Unfortunately, there's no method in the GameOptions family to check whether an option actually exists. Even worse: the return values of Get* methods can be misleading. If GameOptions.GetBool() returns false, there's no way to tell whether that's the actual setting — or just the fallback response for a non-existent option.
So I wrote a small workaround that helps with auto-detection. Note: It doesn’t prevent the “not found” message from appearing in the CET console.
function GameOptions.Has(group, option)
if GameOptions.Get(group, option) ~= "" then
return true
end
return false
end
Some bugs only show up once you launch the game — not while writing your CET mod. You might wonder why the game won’t start and spend half a day hunting for the cause. So I’m documenting these to help others avoid the same traps.
Defining a local variable with a leading underscore in global space can prevent Cyberpunk (and CET) from launching altogether.
local _TRANSPARENCY = ImGui.GetColorU32(0, 0, 0, 0)
Say no to cookies. Say yes to control.
RootPunk is not a website. It's a stance.
No tracking. No third-party scripts. No cookie banners haunting your scroll path. What you get is a clean byte stream from server to brain — built from first principles, without the crutches of modern web abstractions.
The system stores nothing in your browser. No session IDs. No analytics. No fingerprinting.
It doesn’t ask for permission because it doesn’t need any.
Privacy by architecture — not by pop-up.
Everything is rendered server-side.
Even optional behaviors like quotes, previews or audio playback are resolved on the server and only optionally refined by JavaScript — never required.
There’s no “defer JS until ready” here. It’s already ready.
No frameworks. No NPM installs. No runtime bundlers.
Just raw PHP, SSI, and file reads — fast because it was always fast.
If you want to inspect how it works, just view source.
It’s not “minified” — it’s legible.
No loading screens. No infinite loaders. No 5MB of JS for a button.
If something doesn’t need to exist, it doesn't.
RootPunk removes more than it adds — until only clarity remains.
RootPunk isn’t minimalist because it’s cool.
It’s minimalist because it’s tired of pretending websites need to be complicated.
Multithreaded includes. Parallel assembly.
Rootpunk doesn’t render one step at a time — it composes its UI in parallel.
Thanks to NginX’s Server Side Includes (SSI), each <!--#include virtual="..." -->
directive is handled concurrently by separate worker processes. That means your skin styles, navigation logic, Markdown content, random quote, and even base64-injected assets are all fetched and injected at the same time.
This is parallel layout assembly — and it feels instant.
The core loader boot.php includes partials via:
<!--# include virtual="/api/min/skin/root.css" -->
<!--# include virtual="/code/view-css.php?/image" -->
This allows highly granular, dependency-free templating. Since Nginx handles SSI concurrently, each include runs in parallel. You get multi-threaded layout composition without building or bundling anything.
While frontend frameworks rely on hydration and client bootstrapping, Rootpunk resolves everything server-side. That includes:
.css
skin modules via <!--#include virtual="/api/min/skin/*.css" -->
view-list.php
, mad.php
Shared
methodsb64.php
Each include is its own thread, launched by Nginx, then composed into a single HTML payload.
You’re not streaming chunks. You’re parallel-building a terminal UI that just arrives.
READY
)Rootpunk isn’t server-rendered in the classic sense — it’s pre-threaded, composed, and delivered with no client overhead.
Most modern frameworks render HTML on the server, then ship JavaScript to “hydrate” the page — binding event listeners and unlocking interactivity after the fact. Until hydration finishes, the page might look alive but isn’t: buttons don’t respond, inputs fail, nav items are inert.
That’s what RootPunk avoids. There’s no waiting, no progressive wake-up, no fragile dance of scripts and markup.
Your page arrives fully usable from byte one — routed, styled, interactive if needed, and never dependent on JS execution. Even if a slow connection drops halfway through, the content is already rendered and navigable.
Hydration can create beautiful corpses. RootPunk prefers living systems.
Precomputed. Preencoded. Permanently efficient.
In RootPunk, cache isn’t a layer — it’s a design philosophy. There’s no loading spinner, no "checking for updates", no lazy database hooks.
Instead, you encode, compress, hash, and deliver — once.
Icons, fonts and even the silent fallback .mp3 are embedded directly:
echo '<link rel="icon" href="data:image/x-icon;base64,<!--#include file="/api/b64/rp.ico" -->">';
That’s not just compact — it’s an instant content pipeline.
Every file in Rootpunk’s architecture — images, icons, audio — is encoded and cached with deterministic keys based on:
filemtime()
timestamp This ensures that nothing is recalculated unless something actually changed. APCu stores the base64 blobs for a full 7 days, and NginX handles the rest through static caching rules.
$key = 'B64:'.filemtime($file).':'.$file;
apcu_store($key, base64_encode(file_get_contents($file)), 604800);
It's not a cache hit or miss — it's cache like you mean it.
No <link>. No <script src>. No <img src="/favicon.ico">. RootPunk uses <!--#include virtual="/b64/..."> to inject assets inline — browser-decoded, CDN-free. This includes:
Every file becomes a data URL, streamed directly with the page. That’s less “delivered on demand” and more “you already had it.”
Why recalculate what you can remember?
You’re not caching to speed things up — you’re preloading your own brain.
Gallery images (/view-scan.php) are distributed over subdomains:
<img loading="lazy" src="//0x1.rootpunk.com/p[HASH].jpg">
Browsers increase parallel load limits per domain — sharding gives you more lanes on the highway. And since these are hash-based, they’re cacheable indefinitely on the client side.
If an image isn’t found in the local cache? RootPunk renders it on the fly, injects a watermark, writes it into /cache/, and responds with Content-type: image/jpeg.
There’s no fail. Just fallback.
RootPunk doesn’t store assets — it mounts volumes of meaning.
Media is served from a remote 6-Bay SSD NAS connected via NFS, mounted directly into your runtime layout. With over 7TB combined capacity and read speeds that make local disks blink, this setup keeps the main machine light and the payload heavy.
/www/image
→ X.X.X.X:/volume/image/www/music
→ X.X.X.X:/volume/musicAI images and music live externally, but feel local — indexed, hashed, and rendered on demand. Cache warmers like APCu handle re-requests gracefully, and if a NAS share is temporarily offline, Rootpunk degrades with dignity and fallback logic.
You didn’t just add storage — you added remote consciousness.
Each content section (/r
, /ai
, /mod
, /tech
) is pre-routed using CSS <input type="radio">
toggles with corresponding labels. No JavaScript needed for state — it’s handled by the browser’s rendering engine through CSS selectors. Navigation becomes a declarative UI state machine.
echo '<input id="ct-1" name="ct" type="radio" checked>';
echo '<label for="ct-1">/r<br><i>THE ROOT</i></label>';
These inputs allow each section to be toggled via radio IDs — with zero client script.
Optional JS. Maximal intent.
RootPunk isn’t powered by JavaScript — it’s enhanced by it.
All interactive behavior is fully optional and only kicks in when allowed. No UI element needs scripts. But when JS is present, it activates intelligent patterns: inline audio player state, playlist tracking, bootloader visuals, and more — all seamlessly, all featherlight.
The music player responds to play()
, pause()
and ended
— updating the DOM, switching visual state, and even remembering the song quote it replaced.
Playback isn't “streamed” — it’s rendered, and then rehydrated by minimalist logic:
player.addEventListener('play', function(){
document.getElementById("song").innerHTML = titles[family][active];
});
If JS never runs, the original quote remains. If JS runs, the interface breathes.
The system injects dynamic flavor via randomized statements from Shared::GetQuote() — prebuilt in the PHP core and rotated on each reload:
echo '<p id="song">'.Shared::GetQuote().'</p>';
This further proves: no clientside logic, all flavor, full identity.
When a CSS variable says --sw-boots: yes, RootPunk boots. Like, literally — line by line, typing out its own diagnostics panel:
'SYSTEM BOOT v1.1' '>> SYSTEM DIAGNOSTICS' ' CPU ............ OK' ' CACHE .......... SYNCED' ' SHARDS ......... ONLINE'
No frameworks. No dependencies. Just a <div> injected with conviction.
JS Respect Mode
The page:
This isn’t progressive enhancement. This is consensual execution.
The music system even detects and recovers from:
player.addEventListener('error', function(){
if (player.src !== "/music/silence.mp3") {
player.load();
}
});
It’s a playlist built like a rover: it reboots when it coughs.
RootPunk doesn’t need JavaScript. It just treats it like a loyal sidekick — useful, clever, and never in control.