Skip to content

Instantly share code, notes, and snippets.

View Kattoor's full-sized avatar

Jasper Catthoor Kattoor

View GitHub Profile
@Kattoor
Kattoor / pak_onefile_edit.js
Created March 1, 2026 12:31
pak_onefile_edit.js
#!/usr/bin/env node
"use strict";
/**
* Heaps PAK single-file extract + replace (repack)
* Based on heaps: hxd/fmt/pak/Reader.hx, Writer.hx, Build.hx, FileSystem.hx
*
* Commands:
* Extract one file:
* node pak_onefile_edit.js extract <pakFile> "<path/in/pak.ext>" <outFile>
@Kattoor
Kattoor / farever-extractor.js
Created February 24, 2026 22:55
farever-extractor.js
#!/usr/bin/env node
"use strict";
/**
* Extract all assets from a Heaps-style PAK file (like hxd.fmt.pak.Build -x),
* and convert DDS payloads to PNG using texconv.exe (must be in PATH).
*
* Usage:
* node extract-pak.js "C:\path\to\res.pak"
* node extract-pak.js "C:\path\to\res.pak" --out "C:\output\folder"
@Kattoor
Kattoor / bs-image-differ.mjs
Created February 15, 2026 15:42
bs-image-differ.mjs
import fs from "fs";
import crypto from "crypto";
import { decompress } from "@mongodb-js/zstd";
import { Image } from "image-js";
import Bcdec from "./wasm/bcdec.js";
// ---------------- CLI ----------------
const OLD_PATH = process.argv[2];
const NEW_PATH = process.argv[3];
if (!OLD_PATH || !NEW_PATH) {
import {spawn} from 'child_process';
import {EOL} from 'os';
import {request} from 'http';
const assetRipperPath = 'C:\\Users\\jaspe\\Downloads\\AssetRipper\\AssetRipper.GUI.Free.exe';
const assetFolderPath = 'C:\\Program Files (x86)\\Steam\\steamapps\\common\\BitCraft Online Demo';
const outPath = 'C:\\Users\\jaspe\\projects\\bitcraft-assets';
let port;
import {spawn} from 'child_process';
import {EOL} from 'os';
const assetRipperPath = 'C:\\Users\\kattoor\\Downloads\\AssetRipper\\AssetRipper.GUI.Free.exe';
const assetFolderPath = 'C:\\Program Files (x86)\\Steam\\steamapps\\common\\BitCraft Online Demo';
const outPath = 'C:\\Users\\kattoor\\projects\\bitcraft-assets';
let apiBase;
function startAssetRipperAndListenToStdOut(executablePath) {
@Kattoor
Kattoor / dump-bitcraft-wasm.js
Created June 11, 2025 10:53
dump-bitcraft-wasm.js
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
import fs from 'fs';
import {WebSocket} from 'ws';
import {execSync} from 'child_process';
async function getIdentityToken() {
const response = await fetch('https://131.153.155.197/v1/identity', {method: 'POST'});
const {token: identityToken} = await response.json();
return identityToken;
@Kattoor
Kattoor / app.js
Created June 7, 2025 20:18
SpacetimeDB BitCraft example
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
import fs from 'fs';
import {WebSocket} from 'ws';
async function getIdentityToken() {
const response = await fetch('https://131.153.155.197/v1/identity', {method: 'POST'});
const {token: identityToken} = await response.json();
return identityToken;
@Kattoor
Kattoor / gist:d9efe5c5e7b0964d3b70489c6bb85684
Created June 7, 2025 20:17
SpacetimeDB BitCraft example
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
import fs from 'fs';
import {WebSocket} from 'ws';
async function getIdentityToken() {
const response = await fetch('https://131.153.155.197/v1/identity', {method: 'POST'});
const {token: identityToken} = await response.json();
return identityToken;
@Kattoor
Kattoor / index.js
Created February 3, 2025 14:50
Arcanist deserializer
import fs from 'fs';
import createKbuffer from "./kbuffer.js";
import pg from 'pg';
const {Pool} = pg;
const pool = new Pool({
host: 'localhost', port: 5432, user: 'postgres', password: 'nope', database: 'postgres',
});
@Kattoor
Kattoor / index.js
Created February 3, 2025 13:16
Arcanist Replay Downloader
import fs from 'fs';
import https from 'https';
const cutOffDate = '2024-07-15';
const dictionaryFilePath = './replays.json';
const replayFilesOutPath = './replays';
const discordUrl = 'https://discord.com/api/v9/channels/760349009192943656/messages?limit=100';