Compare commits
No commits in common. "fed62b18bcecc57aac987b78cf38352595925c82" and "c66cd9484a0683e4b0ee2adb32375040a2296fca" have entirely different histories.
fed62b18bc
...
c66cd9484a
8 changed files with 201 additions and 205 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -41,6 +41,4 @@ desktop.ini
|
||||||
tools/
|
tools/
|
||||||
update_icon.bat
|
update_icon.bat
|
||||||
update_icon.py
|
update_icon.py
|
||||||
docs_for_claude.json
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
12
README.md
12
README.md
|
|
@ -90,7 +90,7 @@ and `themes/my-theme.css`:
|
||||||
|
|
||||||
### Writing a plugin
|
### Writing a plugin
|
||||||
|
|
||||||
A plugin lives in its own subfolder, `plugins/<plugin-name>/`, with a `manifest.json`, an `index.js`, and optionally a `styles.css`.
|
A plugin lives in its own subfolder in `plugins/<plugin-name>/` with a `manifest.json`, an `index.js`, and an optional companion `styles.css`.
|
||||||
|
|
||||||
`plugins/my-plugin/manifest.json`:
|
`plugins/my-plugin/manifest.json`:
|
||||||
|
|
||||||
|
|
@ -121,10 +121,10 @@ plugin.onDisable = () => {
|
||||||
|
|
||||||
#### What plugins can do
|
#### What plugins can do
|
||||||
|
|
||||||
- **UI and DOM tweaks.** Add buttons, badges, links or panels with the normal DOM APIs. If the plugin folder has a `styles.css`, it's injected when the plugin is enabled and removed when it's disabled.
|
- **UI & DOM tweaks.** Inject custom buttons, badges, links, or panels into CurseForge using standard DOM APIs. If a `styles.css` is present in the plugin folder, it is automatically injected when enabled and removed when disabled.
|
||||||
- **Method patching.** Hook into or replace internal JavaScript functions with `BetterCurseForge.patcher.before()`, `after()` or `instead()`.
|
- **Method patching.** Intercept, modify, or override internal JavaScript functions with `BetterCurseForge.patcher.before()`, `after()`, or `instead()`.
|
||||||
- **Persistent settings.** Save and read preferences across restarts with `BetterCurseForge.settings.get(key)` and `set(key, value)`.
|
- **Persistent settings.** Store and read user preferences across restarts using `BetterCurseForge.settings.get(key)` and `set(key, value)`.
|
||||||
- **Events.** Listen for app lifecycle events with `BetterCurseForge.on(event, callback)`.
|
- **Event listening.** Hook into application lifecycle events using `BetterCurseForge.on(event, callback)`.
|
||||||
|
|
||||||
## Building from source
|
## Building from source
|
||||||
|
|
||||||
|
|
@ -142,7 +142,7 @@ The executable ends up in `dist/BetterCurseForge.exe`.
|
||||||
|
|
||||||
### Syncing changes from GitHub
|
### Syncing changes from GitHub
|
||||||
|
|
||||||
To pull changes from GitHub:
|
To pull down updates made on GitHub:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
git pull origin master
|
git pull origin master
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@ import { defineConfig } from 'vitepress';
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
title: 'BetterCurseForge',
|
title: 'BetterCurseForge',
|
||||||
description: 'Client mod for CurseForge Launcher',
|
description: 'Client mod for CurseForge Launcher',
|
||||||
base: process.env.BASE_URL || '/',
|
base: process.env.BASE_URL || '/BetterCurseForge/',
|
||||||
appearance: 'dark',
|
appearance: 'dark',
|
||||||
lastUpdated: true,
|
lastUpdated: true,
|
||||||
cleanUrls: true,
|
cleanUrls: true,
|
||||||
|
|
||||||
head: [
|
head: [
|
||||||
['link', { rel: 'icon', type: 'image/png', href: (process.env.BASE_URL || '/') + 'logo.png' }],
|
['link', { rel: 'icon', type: 'image/png', href: (process.env.BASE_URL || '/BetterCurseForge/') + 'logo.png' }],
|
||||||
['meta', { name: 'theme-color', content: '#9333ea' }],
|
['meta', { name: 'theme-color', content: '#9333ea' }],
|
||||||
['meta', { name: 'og:type', content: 'website' }],
|
['meta', { name: 'og:type', content: 'website' }],
|
||||||
['meta', { name: 'og:title', content: 'BetterCurseForge' }],
|
['meta', { name: 'og:title', content: 'BetterCurseForge' }],
|
||||||
|
|
@ -23,7 +23,6 @@ export default defineConfig({
|
||||||
nav: [
|
nav: [
|
||||||
{ text: 'Guide', link: '/guide/installation' },
|
{ text: 'Guide', link: '/guide/installation' },
|
||||||
{ text: 'API', link: '/api/' },
|
{ text: 'API', link: '/api/' },
|
||||||
{ text: 'Forgejo', link: 'http://92.5.113.44:3000/tomasalias/BetterCurseForge' },
|
|
||||||
{ text: 'GitHub', link: 'https://github.com/tomasalias/BetterCurseForge' },
|
{ text: 'GitHub', link: 'https://github.com/tomasalias/BetterCurseForge' },
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
# API Reference
|
# API Reference
|
||||||
|
|
||||||
BetterCurseForge adds a global object, `window.BetterCurseForge`, to CurseForge's Electron renderer process. Themes, plugins and your own scripts can use it to inject styles, patch methods, read and write settings, and listen for events.
|
BetterCurseForge exposes a global runtime object on `window.BetterCurseForge` within the CurseForge Electron renderer process. This API allows themes, plugins, and developer scripts to inject styles, monkey-patch methods, manage settings, and listen to application events.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## TypeScript definitions
|
## TypeScript Definition
|
||||||
|
|
||||||
If you're using TypeScript, this gives you types and autocompletion:
|
For TypeScript development and autocompletion:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
declare global {
|
declare global {
|
||||||
|
|
@ -54,7 +54,7 @@ export interface BetterCurseForgeAPI {
|
||||||
### `BetterCurseForge.version`
|
### `BetterCurseForge.version`
|
||||||
|
|
||||||
- **Type**: `string`
|
- **Type**: `string`
|
||||||
- **Description**: Version of the BetterCurseForge runtime that's currently running.
|
- **Description**: The currently running BetterCurseForge runtime version.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
console.log(BetterCurseForge.version); // "1.0.0"
|
console.log(BetterCurseForge.version); // "1.0.0"
|
||||||
|
|
@ -64,11 +64,11 @@ console.log(BetterCurseForge.version); // "1.0.0"
|
||||||
|
|
||||||
### `BetterCurseForge.injectCSS(css)`
|
### `BetterCurseForge.injectCSS(css)`
|
||||||
|
|
||||||
Adds CSS rules to the document `<head>`.
|
Dynamically injects CSS rules into the document `<head>`.
|
||||||
|
|
||||||
- **Parameters**:
|
- **Parameters**:
|
||||||
- `css` *(string)*: The CSS to inject.
|
- `css` *(string)*: Raw CSS string to inject.
|
||||||
- **Returns**: `() => void`. Call it to remove the injected `<style>` tag.
|
- **Returns**: `() => void` — Function that removes the injected `<style>` tag when called.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Inject styles
|
// Inject styles
|
||||||
|
|
@ -86,15 +86,15 @@ uninject();
|
||||||
|
|
||||||
## Settings API (`BetterCurseForge.settings`)
|
## Settings API (`BetterCurseForge.settings`)
|
||||||
|
|
||||||
Persistent configuration, stored in `%APPDATA%\CurseForge\BetterCurseForge\settings.json`.
|
Manages persistent configuration stored in `%APPDATA%\CurseForge\BetterCurseForge\settings.json`.
|
||||||
|
|
||||||
### `settings.get(key?)`
|
### `settings.get(key?)`
|
||||||
|
|
||||||
Returns the setting for `key`, or the whole settings object if you don't pass a key.
|
Retrieves a setting by key, or returns the entire settings object if no key is specified.
|
||||||
|
|
||||||
- **Parameters**:
|
- **Parameters**:
|
||||||
- `key` *(string, optional)*: Name of the setting.
|
- `key` *(string, optional)*: Setting key name.
|
||||||
- **Returns**: `Promise<any>`. The value, or `null` if it isn't set.
|
- **Returns**: `Promise<any>` — Value of the setting, or `null`.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Retrieve a specific value
|
// Retrieve a specific value
|
||||||
|
|
@ -106,12 +106,12 @@ const allSettings = await BetterCurseForge.settings.get();
|
||||||
|
|
||||||
### `settings.set(key, value)`
|
### `settings.set(key, value)`
|
||||||
|
|
||||||
Saves a value and writes it to disk asynchronously.
|
Stores a setting value and writes it asynchronously to disk.
|
||||||
|
|
||||||
- **Parameters**:
|
- **Parameters**:
|
||||||
- `key` *(string)*: Name of the setting.
|
- `key` *(string)*: Setting key name.
|
||||||
- `value` *(any)*: Any JSON-serializable value.
|
- `value` *(any)*: JSON-serializable value.
|
||||||
- **Returns**: `Promise<boolean>`. `true` if the save worked.
|
- **Returns**: `Promise<boolean>` — `true` if saved successfully.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
await BetterCurseForge.settings.set('myPlugin.fontSize', 14);
|
await BetterCurseForge.settings.set('myPlugin.fontSize', 14);
|
||||||
|
|
@ -121,17 +121,17 @@ await BetterCurseForge.settings.set('myPlugin.fontSize', 14);
|
||||||
|
|
||||||
## Patcher API (`BetterCurseForge.patcher`)
|
## Patcher API (`BetterCurseForge.patcher`)
|
||||||
|
|
||||||
Utilities for inspecting, modifying or replacing methods on JavaScript objects and modules. Every function returns an unpatch function.
|
Provides monkey-patching utilities to inspect, modify, or replace methods on JavaScript objects and modules safely.
|
||||||
|
|
||||||
### `patcher.before(obj, method, callback)`
|
### `patcher.before(obj, method, callback)`
|
||||||
|
|
||||||
Runs `callback(args)` **before** the target method is called.
|
Executes `callback(args)` **before** the target method is invoked.
|
||||||
|
|
||||||
- **Parameters**:
|
- **Parameters**:
|
||||||
- `obj` *(object)*: Target object.
|
- `obj` *(object)*: Target object.
|
||||||
- `method` *(string)*: Method name on `obj`.
|
- `method` *(string)*: Method name on `obj`.
|
||||||
- `callback` *(Function)*: `(args) => void`.
|
- `callback` *(Function)*: Function receiving arguments: `(args) => void`.
|
||||||
- **Returns**: `() => void`. Call it to restore the original method.
|
- **Returns**: `() => void` — Unpatch function that restores the original method.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const unpatch = BetterCurseForge.patcher.before(console, 'warn', (args) => {
|
const unpatch = BetterCurseForge.patcher.before(console, 'warn', (args) => {
|
||||||
|
|
@ -146,13 +146,13 @@ unpatch();
|
||||||
|
|
||||||
### `patcher.after(obj, method, callback)`
|
### `patcher.after(obj, method, callback)`
|
||||||
|
|
||||||
Runs `callback(args, result)` **after** the target method. Return a value to replace the method's return value.
|
Executes `callback(args, result)` **after** the target method runs. You can return a new value to replace the method's return value.
|
||||||
|
|
||||||
- **Parameters**:
|
- **Parameters**:
|
||||||
- `obj` *(object)*: Target object.
|
- `obj` *(object)*: Target object.
|
||||||
- `method` *(string)*: Method name on `obj`.
|
- `method` *(string)*: Method name on `obj`.
|
||||||
- `callback` *(Function)*: `(args, result) => any`.
|
- `callback` *(Function)*: `(args, result) => any`.
|
||||||
- **Returns**: `() => void`. Unpatch function.
|
- **Returns**: `() => void` — Unpatch function.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const unpatch = BetterCurseForge.patcher.after(service, 'getTitle', (args, result) => {
|
const unpatch = BetterCurseForge.patcher.after(service, 'getTitle', (args, result) => {
|
||||||
|
|
@ -166,13 +166,13 @@ unpatch();
|
||||||
|
|
||||||
### `patcher.instead(obj, method, callback)`
|
### `patcher.instead(obj, method, callback)`
|
||||||
|
|
||||||
Replaces the target method. The callback gets the arguments and a reference to the original method.
|
Completely overrides the target method. Receives both the incoming arguments and a reference to the original method.
|
||||||
|
|
||||||
- **Parameters**:
|
- **Parameters**:
|
||||||
- `obj` *(object)*: Target object.
|
- `obj` *(object)*: Target object.
|
||||||
- `method` *(string)*: Method name on `obj`.
|
- `method` *(string)*: Method name on `obj`.
|
||||||
- `callback` *(Function)*: `(args, originalFn) => any`.
|
- `callback` *(Function)*: `(args, originalFn) => any`.
|
||||||
- **Returns**: `() => void`. Unpatch function.
|
- **Returns**: `() => void` — Unpatch function.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const unpatch = BetterCurseForge.patcher.instead(target, 'openExternalUrl', (args, originalFn) => {
|
const unpatch = BetterCurseForge.patcher.instead(target, 'openExternalUrl', (args, originalFn) => {
|
||||||
|
|
@ -188,12 +188,12 @@ unpatch();
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Event system (`BetterCurseForge.on / off / emit`)
|
## Event System (`BetterCurseForge.on / off / emit`)
|
||||||
|
|
||||||
BetterCurseForge has an event bus that plugins can use to talk to each other and to react to lifecycle events.
|
BetterCurseForge includes an event bus for inter-plugin and lifecycle communication.
|
||||||
|
|
||||||
### `BetterCurseForge.on(event, callback)`
|
### `BetterCurseForge.on(event, callback)`
|
||||||
Adds a listener for an event.
|
Subscribes a listener to an event.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const onReady = () => console.log('BetterCurseForge is ready!');
|
const onReady = () => console.log('BetterCurseForge is ready!');
|
||||||
|
|
@ -201,14 +201,14 @@ BetterCurseForge.on('ready', onReady);
|
||||||
```
|
```
|
||||||
|
|
||||||
### `BetterCurseForge.off(event, callback)`
|
### `BetterCurseForge.off(event, callback)`
|
||||||
Removes a listener.
|
Unsubscribes a listener.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
BetterCurseForge.off('ready', onReady);
|
BetterCurseForge.off('ready', onReady);
|
||||||
```
|
```
|
||||||
|
|
||||||
### `BetterCurseForge.emit(event, ...args)`
|
### `BetterCurseForge.emit(event, ...args)`
|
||||||
Calls every listener registered for the event.
|
Emits an event to all registered listeners.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
BetterCurseForge.emit('custom-event', { detail: 123 });
|
BetterCurseForge.emit('custom-event', { detail: 123 });
|
||||||
|
|
@ -216,10 +216,10 @@ BetterCurseForge.emit('custom-event', { detail: 123 });
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Subsystem managers
|
## Subsystem Managers
|
||||||
|
|
||||||
### `BetterCurseForge.themes` (`ThemeManager`)
|
### `BetterCurseForge.themes` (`ThemeManager`)
|
||||||
Control custom themes from code:
|
Provides programmatic control over custom themes:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Get all discovered themes
|
// Get all discovered themes
|
||||||
|
|
@ -242,7 +242,7 @@ BetterCurseForge.themes.removeTheme(true);
|
||||||
```
|
```
|
||||||
|
|
||||||
### `BetterCurseForge.plugins` (`PluginManager`)
|
### `BetterCurseForge.plugins` (`PluginManager`)
|
||||||
Control plugins from code:
|
Provides programmatic control over plugins:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Get all installed plugins
|
// Get all installed plugins
|
||||||
|
|
@ -253,7 +253,7 @@ await BetterCurseForge.plugins.togglePlugin('compact-mode');
|
||||||
```
|
```
|
||||||
|
|
||||||
### `BetterCurseForge.ads` (`AdBlocker`)
|
### `BetterCurseForge.ads` (`AdBlocker`)
|
||||||
The internal ad blocker runtime:
|
Internal ad blocker runtime:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Contains zero-ad CSS rules and ad container cleanup handlers
|
// Contains zero-ad CSS rules and ad container cleanup handlers
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,51 @@
|
||||||
# Installation & Usage
|
# Installation & Usage
|
||||||
|
|
||||||
How to install, check, and remove **BetterCurseForge**, using either the desktop app or the command line.
|
This guide covers installing, managing, and uninstalling **BetterCurseForge** using either the desktop GUI application or the command-line interface.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
You need:
|
Before using BetterCurseForge, make sure you have:
|
||||||
|
|
||||||
- **Windows 10 or Windows 11** (64-bit)
|
- **Windows 10 or Windows 11** (64-bit)
|
||||||
- **CurseForge Launcher** installed (standalone or Overwolf edition)
|
- **CurseForge Launcher** installed (standalone or Overwolf edition)
|
||||||
- CurseForge closed when you run the patcher
|
- CurseForge closed before running the patcher
|
||||||
|
|
||||||
::: tip BACKUPS
|
::: tip SAFE & 100% REVERSIBLE
|
||||||
Before it changes anything, BetterCurseForge saves untouched copies of the original files at `resources/app.asar.vanilla` and `CurseForge.exe.vanilla`. You can go back to stock CurseForge whenever you want, with one click.
|
Before modifying any files, BetterCurseForge creates untouched vanilla backups at `resources/app.asar.vanilla` and `CurseForge.exe.vanilla`. You can cleanly revert to stock CurseForge at any time with a single click.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Option 1: Desktop GUI (recommended)
|
## Method 1: Using the Desktop GUI (Recommended)
|
||||||
|
|
||||||
BetterCurseForge is a single executable with a dark-themed GUI.
|
BetterCurseForge comes as a standalone desktop executable with a sleek, dark-themed graphical interface.
|
||||||
|
|
||||||
### Step 1: Download `BetterCurseForge.exe`
|
### Step 1: Download `BetterCurseForge.exe`
|
||||||
|
|
||||||
Grab the latest build from the releases page:
|
Download the latest executable from the official releases:
|
||||||
|
|
||||||
- [Download `BetterCurseForge.exe`](https://github.com/tomasalias/BetterCurseForge/releases/latest)
|
- [Download `BetterCurseForge.exe`](https://github.com/tomasalias/BetterCurseForge/releases/latest)
|
||||||
|
|
||||||
Put it anywhere you like (Downloads, a tools folder, the desktop).
|
Place it in any convenient folder (e.g., Downloads, Tools, or desktop).
|
||||||
|
|
||||||
### Step 2: Open BetterCurseForge
|
### Step 2: Open BetterCurseForge
|
||||||
|
|
||||||
Double-click `BetterCurseForge.exe` to open it.
|
Double-click `BetterCurseForge.exe` to launch the application.
|
||||||
|
|
||||||
{width=64 style="display:block;margin:1rem auto;"}
|
{width=64 style="display:block;margin:1rem auto;"}
|
||||||
|
|
||||||
On startup it:
|
The application automatically:
|
||||||
- Finds your CurseForge install folder through the Windows Registry.
|
- Detects your CurseForge installation folder from the Windows Registry.
|
||||||
- Checks whether CurseForge is vanilla or patched.
|
- Checks whether your client is currently vanilla or patched.
|
||||||
- Shows the installed CurseForge version and install directory.
|
- Displays the installed CurseForge version and installation directory.
|
||||||
|
|
||||||
### Step 3: Click "Patch CurseForge"
|
### Step 3: Click "Patch CurseForge"
|
||||||
|
|
||||||
1. Click the **Patch CurseForge** button.
|
1. Click the **Patch CurseForge** button.
|
||||||
2. The patcher closes any running CurseForge processes, backs up the vanilla files, applies the patch (ad blocking, theme engine, skin unlocks, plugin loader), updates the integrity signature in the executable, and repacks the app.
|
2. The patcher will close any running CurseForge processes, create a vanilla backup, apply all enhancements (ad removal, theme engine, premium unlocks, and plugin loader), update the executable integrity signature, and repack the application.
|
||||||
3. The log panel shows progress as it goes:
|
3. You will see live output in the log panel confirming:
|
||||||
```text
|
```text
|
||||||
[+] Found CurseForge at: C:\Users\Username\AppData\Local\Programs\CurseForge Windows
|
[+] Found CurseForge at: C:\Users\Username\AppData\Local\Programs\CurseForge Windows
|
||||||
[+] Unlocked native premium themes (2 route checks)
|
[+] Unlocked native premium themes (2 route checks)
|
||||||
|
|
@ -60,17 +60,17 @@ On startup it:
|
||||||
[+] Auto-repatch watcher active and persistent across updates.
|
[+] Auto-repatch watcher active and persistent across updates.
|
||||||
[*] CurseForge successfully patched! Ads removed, themes & plugins enabled.
|
[*] CurseForge successfully patched! Ads removed, themes & plugins enabled.
|
||||||
```
|
```
|
||||||
4. Click **Launch CurseForge** or start it from your usual shortcut. That's it.
|
4. Click **Launch CurseForge** or open your usual desktop shortcut—you're done!
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Option 2: Command line
|
## Method 2: Command-Line Interface (CLI)
|
||||||
|
|
||||||
If you want to script it or run it without the GUI, `BetterCurseForge.exe` has a CLI.
|
For automated workflows, scripting, or headless environments, `BetterCurseForge.exe` provides a comprehensive CLI:
|
||||||
|
|
||||||
### Patching
|
### Patching via Terminal
|
||||||
|
|
||||||
Open PowerShell or Command Prompt in the folder with `BetterCurseForge.exe`:
|
Open PowerShell or Command Prompt in the folder containing `BetterCurseForge.exe`:
|
||||||
|
|
||||||
::: code-group
|
::: code-group
|
||||||
|
|
||||||
|
|
@ -84,9 +84,9 @@ BetterCurseForge.exe patch
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Checking status
|
### Checking Status
|
||||||
|
|
||||||
See whether CurseForge is patched:
|
Verify whether your client is patched:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\BetterCurseForge.exe status
|
.\BetterCurseForge.exe status
|
||||||
|
|
@ -101,26 +101,26 @@ ASAR Hash: Verified
|
||||||
|
|
||||||
### Unpatching
|
### Unpatching
|
||||||
|
|
||||||
Go back to stock CurseForge:
|
Restore your vanilla CurseForge client:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\BetterCurseForge.exe unpatch
|
.\BetterCurseForge.exe unpatch
|
||||||
```
|
```
|
||||||
|
|
||||||
This restores `resources/app.asar` from the vanilla backup and re-verifies the original executable signatures.
|
This restores `resources/app.asar` from the vanilla backup and re-verifies original executable signatures.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Auto-repatch after CurseForge updates
|
## Auto-Repatch: Surviving CurseForge Updates
|
||||||
|
|
||||||
When CurseForge updates itself, it overwrites `app.asar` with a stock copy and restarts.
|
When the official CurseForge Launcher downloads an automatic update, it overwrites `app.asar` with an unpatched version and attempts to restart.
|
||||||
|
|
||||||
BetterCurseForge handles this without the unpatched launcher ever showing up on screen.
|
BetterCurseForge provides an autonomous, smooth transition with **zero screen flashing**:
|
||||||
|
|
||||||
### Managing it in the GUI
|
### Managing Auto-Repatch in the GUI
|
||||||
- Toggle the **Auto-Repatch on Update** button in the app. It turns green when it's on.
|
- In the BetterCurseForge desktop application, simply toggle the **Auto-Repatch on Update** button (turns green when active).
|
||||||
|
|
||||||
### Managing it from the CLI
|
### Managing Auto-Repatch via CLI
|
||||||
```powershell
|
```powershell
|
||||||
# Run the background watcher daemon directly:
|
# Run the background watcher daemon directly:
|
||||||
.\BetterCurseForge.exe watch
|
.\BetterCurseForge.exe watch
|
||||||
|
|
@ -133,18 +133,18 @@ BetterCurseForge handles this without the unpatched launcher ever showing up on
|
||||||
.\BetterCurseForge.exe unpatch # Restores vanilla client and stops watcher
|
.\BetterCurseForge.exe unpatch # Restores vanilla client and stops watcher
|
||||||
```
|
```
|
||||||
|
|
||||||
### How it works
|
### How Auto-Repatch Works
|
||||||
1. **Background watcher**: Runs in the background on Windows directory change notifications and periodic heartbeat checks, so CPU use is negligible.
|
1. **Background Watcher**: Runs silently with 0% CPU consumption via Windows directory event notifications and heartbeat checks.
|
||||||
2. **Killing the stock launcher**: Once it sees an update or an unpatched install, the watcher polls every 150 ms with Win32 process enumeration. If the installer starts `CurseForge.exe`, the watcher kills it within 50 ms, before a window can appear.
|
2. **Active Vanilla Interceptor**: When an update or unpatched state is detected, the patcher polls every 150ms using Win32 kernel process enumeration. If the installer launches `CurseForge.exe`, it is killed within 50ms before any window or frame can appear.
|
||||||
3. **Splash window**: A dark `#121214` card shows the app icon, a purple `AUTO-UPDATE` badge, a progress bar, and status messages while it extracts, unlocks themes, blocks ads and repacks.
|
3. **Dedicated Splash Updater GUI**: A modern, dark-themed `#121214` card appears on screen displaying the application icon, a purple `AUTO-UPDATE` badge, an animated progress bar, and real-time status messages while extracting, unlocking themes, removing ads, and repacking.
|
||||||
4. **Offline repatch**: Extracting and repacking the ASAR takes 2–3 seconds and needs no internet. It uses the Node v24 runtime bundled with CurseForge (`ELECTRON_RUN_AS_NODE=1`) and writes the new `OWEASARSIG` hash into `CurseForge.exe`.
|
4. **Offline Zero-Delay Engine**: Offline ASAR extraction and repacking complete in 2–3 seconds using CurseForge's built-in Node v24 runtime (`ELECTRON_RUN_AS_NODE=1`), synchronizing the `OWEASARSIG` hash directly inside `CurseForge.exe`.
|
||||||
5. **Relaunch**: The patched CurseForge opens and the splash window closes.
|
5. **Seamless Relaunch**: The patched BetterCurseForge client opens automatically, and the splash window gracefully closes.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Under the hood
|
## How It Works Under the Hood
|
||||||
|
|
||||||
Recent CurseForge versions verify the integrity of `app.asar` from inside `CurseForge.exe`. This is the patch flow:
|
Modern versions of CurseForge include **ASAR Code Integrity Verification** enforced directly inside `CurseForge.exe`:
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
|
|
@ -158,19 +158,19 @@ flowchart TD
|
||||||
H --> I["Launch Modded CurseForge with Full Permissions"]
|
H --> I["Launch Modded CurseForge with Full Permissions"]
|
||||||
```
|
```
|
||||||
|
|
||||||
1. **Ad blocking**: Ad requests are blocked at the Electron session level (`session.webRequest`), and CSS collapses the ad frames to 0px. The elements stay in the DOM, so React Fiber's reconciliation isn't affected.
|
1. **Multi-Layer Ad Elimination**: Blocks ad network requests at the Electron session level (`session.webRequest`) and collapses ad frames to 0px using CSS rules, completely preserving React Fiber virtual DOM reconciliation.
|
||||||
2. **Skin unlock**: AST and regex matching, written to tolerate version changes, unlocks the official CurseForge skins (*Pixelforge*, *Lifeforge*, *Fantasyforge*, *Halloween*, etc.) in **Settings -> Themes**.
|
2. **Premium Skin Unlock**: Uses version-resilient AST/regex matching to unlock all official CurseForge skins (*Pixelforge*, *Lifeforge*, *Fantasyforge*, *Halloween*, etc.) in **Settings -> Themes**.
|
||||||
3. **ASAR signature update**: It computes the SHA256 hash of the modified ASAR header and writes it into `CurseForge.exe`, so Electron starts without integrity errors.
|
3. **ASAR Signature Synchronization**: Calculates the cryptographic SHA256 hash of the modified ASAR archive header and writes the new signature directly into `CurseForge.exe`, ensuring Electron boots without security errors or corruption alerts.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting & FAQ
|
||||||
|
|
||||||
::: details How do I tell it's working?
|
::: details How do I verify BetterCurseForge is running?
|
||||||
1. Open CurseForge.
|
1. Open CurseForge.
|
||||||
2. There should be no banner ads or video sponsor frames.
|
2. Notice the total absence of banner ads and video sponsor frames.
|
||||||
3. Go to **Settings -> Themes**. You should see a **Client Themes** section with *Purple Night* in it, and the *Premium* skins (*Pixelforge*, *Lifeforge*, etc.) unlocked.
|
3. Navigate to **Settings -> Themes**: you will see the **Client Themes** section with *Purple Night* available, as well as unlocked *Premium* skins (*Pixelforge*, *Lifeforge*, etc.).
|
||||||
4. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> to open DevTools. The console should print:
|
4. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> to open DevTools. The console will display:
|
||||||
```text
|
```text
|
||||||
[BetterCF] Initializing renderer runtime...
|
[BetterCF] Initializing renderer runtime...
|
||||||
[BetterCF] Theme manager ready (1 theme(s) found). Active: purple-night.css
|
[BetterCF] Theme manager ready (1 theme(s) found). Active: purple-night.css
|
||||||
|
|
@ -178,10 +178,10 @@ flowchart TD
|
||||||
```
|
```
|
||||||
:::
|
:::
|
||||||
|
|
||||||
::: details Antivirus flags the exe
|
::: details Antivirus false-positive warning
|
||||||
Some antivirus tools flag `BetterCurseForge.exe` as a false positive. It looks at running processes (`CurseForge.exe`), reads the Windows Registry to find the install path, and rewrites hashes in an executable, which is the kind of thing heuristic scanners react to. The project is open source: the Python code is in `patcher/`, and you can read it and build the exe yourself.
|
Because `BetterCurseForge.exe` inspects running processes (`CurseForge.exe`), accesses the Windows Registry to locate install paths, and updates executable hashes, some heuristic scanners may flag it. BetterCurseForge is completely open source and safe. You can inspect the entire Python codebase in `patcher/` and build it yourself.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
::: details Permission denied / EPERM error
|
::: details Permission denied / EPERM error
|
||||||
If CurseForge is installed under `C:\Program Files`, the patcher needs Administrator permissions to change files. Right-click `BetterCurseForge.exe` and choose **Run as Administrator**.
|
If your CurseForge launcher is installed under `C:\Program Files`, modifying files requires Administrator permissions. Right-click `BetterCurseForge.exe` and select **Run as Administrator**.
|
||||||
:::
|
:::
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
# Writing Plugins
|
# Writing Plugins
|
||||||
|
|
||||||
Plugins are small JavaScript modules that run inside CurseForge. They can change the DOM, patch methods at runtime, and save settings between sessions.
|
BetterCurseForge features a lightweight plugin system that allows you to extend CurseForge Launcher functionality, manipulate the DOM, hook runtime methods, and persist configuration.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Plugin folder
|
## Plugin Directory Structure
|
||||||
|
|
||||||
Plugins live in the BetterCurseForge user directory:
|
Plugins are stored in the BetterCurseForge user directory:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
%APPDATA%\CurseForge\BetterCurseForge\plugins\
|
%APPDATA%\CurseForge\BetterCurseForge\plugins\
|
||||||
```
|
```
|
||||||
|
|
||||||
Each plugin gets its own subfolder:
|
Each plugin lives in its own dedicated subfolder:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
plugins/
|
plugins/
|
||||||
|
|
@ -22,13 +22,13 @@ plugins/
|
||||||
└── styles.css # Optional: Companion stylesheet
|
└── styles.css # Optional: Companion stylesheet
|
||||||
```
|
```
|
||||||
|
|
||||||
The **Open Plugins Folder** button in the desktop app opens it.
|
You can open the plugins folder directly from the BetterCurseForge desktop GUI by clicking **Open Plugins Folder**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Manifest (`manifest.json`)
|
## Plugin Manifest (`manifest.json`)
|
||||||
|
|
||||||
`manifest.json` describes the plugin:
|
The `manifest.json` file declares your plugin's metadata:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -42,22 +42,22 @@ The **Open Plugins Folder** button in the desktop app opens it.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fields
|
### Manifest Fields
|
||||||
|
|
||||||
| Field | Type | Required | Description |
|
| Field | Type | Required | Description |
|
||||||
| :--- | :--- | :--- | :--- |
|
| :--- | :--- | :--- | :--- |
|
||||||
| `name` | `string` | **Yes** | Name shown in the management UI. |
|
| `name` | `string` | **Yes** | Display name shown in the management UI. |
|
||||||
| `version` | `string` | **Yes** | Semantic version (e.g. `1.0.0`). |
|
| `version` | `string` | **Yes** | Semantic version string (e.g. `1.0.0`). |
|
||||||
| `description` | `string` | No | Short summary of what the plugin does. |
|
| `description` | `string` | No | Brief summary of what the plugin accomplishes. |
|
||||||
| `author` | `string` | No | Author name or handle. |
|
| `author` | `string` | No | Author name or handle. |
|
||||||
| `main` | `string` | No | Entry script. Defaults to `index.js`. |
|
| `main` | `string` | No | Entry JavaScript file. Defaults to `index.js`. |
|
||||||
| `styles` | `string` | No | Stylesheet that's injected automatically when the plugin is enabled. Defaults to `styles.css`. |
|
| `styles` | `string` | No | Companion stylesheet injected automatically on enable. Defaults to `styles.css`. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lifecycle
|
## Plugin Lifecycle & Execution
|
||||||
|
|
||||||
A plugin's script runs when the plugin is enabled. It gets the `BetterCurseForge` API and a `plugin` context object:
|
Plugin scripts are executed when enabled, receiving the `BetterCurseForge` global API and a `plugin` context object:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// index.js
|
// index.js
|
||||||
|
|
@ -73,16 +73,16 @@ plugin.onDisable = () => {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
::: tip STYLESHEETS
|
::: tip AUTOMATIC STYLE INJECTION & REMOVAL
|
||||||
If your plugin folder has a `styles.css` (or the file named in `"styles"` in `manifest.json`), BetterCurseForge injects it into `<head>` when the plugin is enabled and removes it when the plugin is disabled. You don't need to inject or clean it up yourself.
|
If your plugin folder contains a `styles.css` (or file declared in `"styles"` in `manifest.json`), BetterCurseForge automatically injects it into `<head>` when your plugin is enabled and removes it when disabled! You do not need to manually inject or clean up companion stylesheets.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Plugin API
|
## BetterCurseForge Plugin APIs
|
||||||
|
|
||||||
### 1. `BetterCurseForge.injectCSS(css)`
|
### 1. `BetterCurseForge.injectCSS(css)`
|
||||||
Injects CSS into `<head>`. Returns a function that removes the style tag:
|
Injects custom CSS dynamically into `<head>`. Returns a cleanup function that unmounts the style tag:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const removeStyles = BetterCurseForge.injectCSS(`
|
const removeStyles = BetterCurseForge.injectCSS(`
|
||||||
|
|
@ -98,7 +98,7 @@ plugin.onDisable = () => {
|
||||||
---
|
---
|
||||||
|
|
||||||
### 2. `BetterCurseForge.settings`
|
### 2. `BetterCurseForge.settings`
|
||||||
Reads and writes settings that are saved to disk (`settings.json`):
|
Stores and retrieves persistent settings saved to disk (`settings.json`):
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Retrieve a stored setting (or null if not set)
|
// Retrieve a stored setting (or null if not set)
|
||||||
|
|
@ -111,10 +111,10 @@ await BetterCurseForge.settings.set('compactMode.density', 'ultra');
|
||||||
---
|
---
|
||||||
|
|
||||||
### 3. `BetterCurseForge.patcher`
|
### 3. `BetterCurseForge.patcher`
|
||||||
Helpers for monkey-patching methods on objects. Each call returns a function that undoes the patch:
|
Safe method monkey-patching for objects and functions:
|
||||||
|
|
||||||
#### `patcher.before(object, methodName, callback)`
|
#### `patcher.before(object, methodName, callback)`
|
||||||
Runs your callback before the original method. The callback gets `(args)`:
|
Runs your callback before the target method executes. Receives `(args)`:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const unpatch = BetterCurseForge.patcher.before(console, 'error', (args) => {
|
const unpatch = BetterCurseForge.patcher.before(console, 'error', (args) => {
|
||||||
|
|
@ -125,7 +125,7 @@ plugin.onDisable = () => unpatch();
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `patcher.after(object, methodName, callback)`
|
#### `patcher.after(object, methodName, callback)`
|
||||||
Runs after the original method. The callback gets `(args, result)` and can return a new value to replace the result:
|
Runs after the target method completes. Receives `(args, result)`. You can return a modified value:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const unpatch = BetterCurseForge.patcher.after(targetObj, 'getItemTitle', (args, result) => {
|
const unpatch = BetterCurseForge.patcher.after(targetObj, 'getItemTitle', (args, result) => {
|
||||||
|
|
@ -136,7 +136,7 @@ plugin.onDisable = () => unpatch();
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `patcher.instead(object, methodName, callback)`
|
#### `patcher.instead(object, methodName, callback)`
|
||||||
Replaces the original method. The callback gets `(args, originalMethod)`:
|
Completely supersedes the target method. Receives `(args, originalMethod)`:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const unpatch = BetterCurseForge.patcher.instead(targetObj, 'fetchData', (args, originalFn) => {
|
const unpatch = BetterCurseForge.patcher.instead(targetObj, 'fetchData', (args, originalFn) => {
|
||||||
|
|
@ -150,7 +150,7 @@ plugin.onDisable = () => unpatch();
|
||||||
---
|
---
|
||||||
|
|
||||||
### 4. `BetterCurseForge.on(event, callback)` / `.off()` / `.emit()`
|
### 4. `BetterCurseForge.on(event, callback)` / `.off()` / `.emit()`
|
||||||
An event emitter shared across the app:
|
Application-wide event emitter:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const onReady = () => console.log('CurseForge UI is fully loaded!');
|
const onReady = () => console.log('CurseForge UI is fully loaded!');
|
||||||
|
|
@ -164,9 +164,9 @@ plugin.onDisable = () => {
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Example: Compact Mode
|
## Complete Example: Compact Mode Plugin
|
||||||
|
|
||||||
This plugin makes CurseForge's layout denser.
|
This plugin adds a high-density layout mode to CurseForge.
|
||||||
|
|
||||||
::: code-group
|
::: code-group
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,33 @@
|
||||||
# Themes
|
# Custom Themes & Theming Guide
|
||||||
|
|
||||||
BetterCurseForge can load custom themes and reload them live. A theme is a CSS file, optionally with a JSON manifest, and it appears in CurseForge's own theme settings.
|
BetterCurseForge features a native, live-reloading theming engine. Themes allow you to completely restyle the CurseForge Launcher using standard CSS and theme manifests, fully integrated into the official user interface.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Picking a theme
|
## In-App Theme Selector
|
||||||
|
|
||||||
Client themes are added to CurseForge's own **Settings -> Themes** page.
|
BetterCurseForge embeds client themes directly into CurseForge's native **Settings -> Themes** menu.
|
||||||
|
|
||||||
### Finding client themes
|
### How to Access Client Themes
|
||||||
1. Open CurseForge.
|
1. Open CurseForge Launcher.
|
||||||
2. Click the **Settings** gear icon in the bottom-left corner.
|
2. Click the **Settings** gear icon in the bottom-left corner.
|
||||||
3. Choose **Themes** in the settings sidebar.
|
3. Select **Themes** from the settings sidebar.
|
||||||
4. Scroll past the *Classic*, *Colorblind* and *Premium* categories to reach **Client Themes**:
|
4. Scroll down past the *Classic*, *Colorblind*, and *Premium* categories to find the **Client Themes** section:
|
||||||
|
|
||||||
{width=48 style="display:block;margin:1rem auto;"}
|
{width=48 style="display:block;margin:1rem auto;"}
|
||||||
|
|
||||||
### What the theme page does
|
### Native Features in Settings -> Themes
|
||||||
- **Hover preview**: Hover over a theme card to preview it across the whole launcher. Move the cursor away to revert, or click to apply it.
|
- **Live Hover Preview**: Hovering your cursor over any theme card immediately previews the theme across the entire launcher in real time. Move your cursor away to revert, or click to apply.
|
||||||
- **One theme at a time**: Picking a client theme deselects any native skin, and the other way around.
|
- **Mutual Exclusivity**: Selecting a client theme seamlessly deselects native skins, and vice versa. Only one theme is active at a time.
|
||||||
- **Open Folder button**: Opens your themes folder in Explorer so you can drop in new stylesheets.
|
- **"Open Folder" Button**: Directly opens your themes folder in Windows Explorer so you can drop in new stylesheets.
|
||||||
- **Refresh button**: Reloads your custom themes from disk, no restart needed.
|
- **"Refresh" Button**: Reloads all installed custom themes from disk instantly without needing to restart CurseForge.
|
||||||
- **Premium themes unlocked**: The official Premium themes (*Pixelforge*, *Lifeforge*, *Fantasyforge* and *Spookyforge*) are unlocked and free to use.
|
- **Native Premium Themes Unlocked**: All official CurseForge Premium themes (*Pixelforge*, *Lifeforge*, *Fantasyforge*, and *Spookyforge*) are permanently unlocked and free to use!
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Theme folder
|
## Theme Folder Location
|
||||||
|
|
||||||
Themes live in your user application data directory:
|
Themes are stored in your user application data directory:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
%APPDATA%\CurseForge\BetterCurseForge\themes\
|
%APPDATA%\CurseForge\BetterCurseForge\themes\
|
||||||
|
|
@ -38,16 +38,16 @@ Full path:
|
||||||
C:\Users\<YourUsername>\AppData\Roaming\CurseForge\BetterCurseForge\themes\
|
C:\Users\<YourUsername>\AppData\Roaming\CurseForge\BetterCurseForge\themes\
|
||||||
```
|
```
|
||||||
|
|
||||||
The **Open Folder** button in **Settings -> Themes** opens it for you.
|
You can open this folder anytime by clicking the **Open Folder** button in **Settings -> Themes**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Theme layout
|
## Theme File Structure
|
||||||
|
|
||||||
There are two ways to lay out a theme:
|
BetterCurseForge supports two convenient formats:
|
||||||
|
|
||||||
### 1. Single file (recommended)
|
### 1. Single-File Theme (Recommended)
|
||||||
Put a `.css` file in `themes/`, with an optional `.json` manifest next to it:
|
Place a `.css` file in the `themes/` directory, with an optional accompanying `.json` manifest:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
themes/
|
themes/
|
||||||
|
|
@ -55,8 +55,8 @@ themes/
|
||||||
└── purple-night.json (optional metadata & preview colors)
|
└── purple-night.json (optional metadata & preview colors)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Folder
|
### 2. Folder-Based Theme
|
||||||
Make a folder inside `themes/` containing `theme.css` and `theme.json`:
|
Create a folder inside `themes/` with a `theme.css` and `theme.json`:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
themes/
|
themes/
|
||||||
|
|
@ -68,9 +68,9 @@ themes/
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Manifest (`theme.json`)
|
## Theme Manifest Format (`theme.json`)
|
||||||
|
|
||||||
The manifest holds the theme's metadata and the colors of the small preview card shown in **Settings -> Themes**:
|
A `.json` manifest provides metadata and defines the miniature preview card colors shown in the **Settings -> Themes** menu:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -85,78 +85,78 @@ The manifest holds the theme's metadata and the colors of the small preview card
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fields
|
### Manifest Fields
|
||||||
|
|
||||||
| Field | Type | Description |
|
| Field | Type | Description |
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
| `name` | `string` | Name shown on the theme card and in settings. |
|
| `name` | `string` | Display name shown on the theme card and in settings. |
|
||||||
| `version` | `string` | Semantic version (e.g. `1.0.0`). |
|
| `version` | `string` | Semantic version string (e.g. `1.0.0`). |
|
||||||
| `description` | `string` | Short description, shown as a tooltip when you hover the title. |
|
| `description` | `string` | Short tooltip description displayed when hovering the title. |
|
||||||
| `author` | `string` | Author name or handle. |
|
| `author` | `string` | Author name or handle. |
|
||||||
| `primaryColor` | `string` | Hex color of the square icon on the preview card. |
|
| `primaryColor` | `string` | Hex color for the primary square icon in the thumbnail card. |
|
||||||
| `titleColor` | `string` | Hex color of the top bar on the preview card. |
|
| `titleColor` | `string` | Hex color for the top bar in the thumbnail card. |
|
||||||
| `bodyColor` | `string` | Hex color of the lower text bar on the preview card. |
|
| `bodyColor` | `string` | Hex color for the lower text bar in the thumbnail card. |
|
||||||
| `backgroundColor`| `string` | Hex background color of the preview card. |
|
| `backgroundColor`| `string` | Hex background color for the thumbnail card itself. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## CSS variables
|
## CurseForge CSS Variables Reference
|
||||||
|
|
||||||
CurseForge is styled with CSS custom properties. Overriding them lets you theme most of the app without touching individual class names.
|
CurseForge is styled using CSS Custom Properties (variables). Overriding these variables allows you to theme 95% of the application cleanly without touching individual class names.
|
||||||
|
|
||||||
### Brand & accents
|
### Brand & Accents
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| `--surface-brand-brand` | Main brand accent: active tabs, primary buttons, indicators. |
|
| `--surface-brand-brand` | Primary brand accent (active tabs, primary buttons, indicators). |
|
||||||
| `--surface-brand-brand-hover` | Hover state for brand-colored elements. |
|
| `--surface-brand-brand-hover` | Hover state for brand-colored elements. |
|
||||||
| `--color-primary` | Main accent color. |
|
| `--color-primary` | Main accent color. |
|
||||||
| `--color-accent` | Secondary highlight color. |
|
| `--color-accent` | Secondary highlight color. |
|
||||||
| `--selected-item-border` | Border style for selected items and active inputs. |
|
| `--selected-item-border` | Border style for selected items and active inputs. |
|
||||||
|
|
||||||
### Surfaces & backgrounds
|
### Surfaces & Backgrounds
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| `--color-background` | Main app background (content views, modpack library). |
|
| `--color-background` | Main application background (content views, modpack library). |
|
||||||
| `--surface-base` | Darkest background layer (scroll tracks, container bases). |
|
| `--surface-base` | Darkest background layer (scroll tracks, container bases). |
|
||||||
| `--surface-primary` | Raised surface (sidebars, sub-panels). |
|
| `--surface-primary` | Elevated primary surface (sidebars, sub-panels). |
|
||||||
| `--surface-secondary` | Second surface layer (navigation menus, dialog panels). |
|
| `--surface-secondary` | Secondary surface layer (navigation menus, dialog panels). |
|
||||||
| `--surface-tertiery` | Third surface layer (mod cards, list row containers). |
|
| `--surface-tertiery` | Tertiary surface layer (mod cards, list row containers). |
|
||||||
| `--surface-on-surface` | Faint translucent overlay for buttons (`rgba(...)`). |
|
| `--surface-on-surface` | Subtle translucent overlay for buttons (`rgba(...)`). |
|
||||||
| `--surface-on-surface-hover` | Translucent hover overlay for buttons. |
|
| `--surface-on-surface-hover` | Translucent hover overlay for buttons. |
|
||||||
|
|
||||||
### Modpack & library cards
|
### Modpack & Library Cards
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| `--surface-card` | Base background of modpack and project cards. |
|
| `--surface-card` | Modpack / project card base background. |
|
||||||
| `--surface-card-hover` | Background when hovering over a modpack card. |
|
| `--surface-card-hover` | Background color when hovering over modpack cards. |
|
||||||
| `--color-surface-card-active` | Active or clicked state of a card. |
|
| `--color-surface-card-active` | Active or clicked state for card items. |
|
||||||
|
|
||||||
### Typography & text
|
### Typography & Text
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| `--text-pure` | Pure white text (`#ffffff`). |
|
| `--text-pure` | Pure white text (`#ffffff`). |
|
||||||
| `--text-primary` | Main readable text color. |
|
| `--text-primary` | Primary readable text color. |
|
||||||
| `--color-text-title` | Headings, modpack titles, section names. |
|
| `--color-text-title` | Headings, modpack titles, section names. |
|
||||||
| `--color-text-body` | Normal body and description text. |
|
| `--color-text-body` | Standard body and description text. |
|
||||||
| `--color-text-secondary` | Subtitles, authors, version numbers. |
|
| `--color-text-secondary` | Subtitles, authors, version numbers. |
|
||||||
|
|
||||||
### Title bar & navigation
|
### Title Bar & Navigation
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| `--title-bar-background` | Background color or gradient of the window title bar. |
|
| `--title-bar-background` | Background color or gradient for the top window title bar. |
|
||||||
| `--btn-window-action` | Icons on the minimize, maximize and close buttons. |
|
| `--btn-window-action` | Minimize, maximize, and close button icons. |
|
||||||
| `--color-scrollbar-thumb` | Scrollbar thumb color. |
|
| `--color-scrollbar-thumb` | Scrollbar thumb handle color. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Example: Emerald Night
|
## Example Theme: Emerald Night
|
||||||
|
|
||||||
A full working theme. Save the stylesheet as `emerald-night.css` and the manifest as `emerald-night.json`:
|
Here is a complete, working theme stylesheet you can save as `emerald-night.css`:
|
||||||
|
|
||||||
::: code-group
|
::: code-group
|
||||||
|
|
||||||
|
|
@ -237,12 +237,12 @@ button[class*="primary"]:not([class*="secondary"]):hover {
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Inspecting elements
|
## Tips for Inspecting Elements
|
||||||
|
|
||||||
CurseForge is an Electron and React app, so you can inspect its UI with Chromium DevTools:
|
Because CurseForge runs on Electron and React, you can inspect any UI element using Chromium DevTools:
|
||||||
|
|
||||||
1. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> in CurseForge to open DevTools.
|
1. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> in CurseForge to open DevTools.
|
||||||
2. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>C</kbd> to turn on the element inspector.
|
2. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>C</kbd> to activate the element inspector.
|
||||||
3. Click a button, banner, header or list item to see its computed styles and classes in the **Elements** panel.
|
3. Click on any button, banner, header, or list item to reveal its computed styles and classes in the **Elements** panel.
|
||||||
4. Try CSS changes in the **Styles** tab before adding them to your theme.
|
4. Test CSS changes live in the **Styles** tab before adding them to your theme file.
|
||||||
5. In **Settings -> Themes**, click **Refresh** to load your updated stylesheet.
|
5. In **Settings -> Themes**, click **Refresh** to instantly apply your modified theme stylesheet!
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ layout: home
|
||||||
|
|
||||||
hero:
|
hero:
|
||||||
name: "BetterCurseForge"
|
name: "BetterCurseForge"
|
||||||
text: "A client mod for the CurseForge launcher"
|
text: "Client mod for CurseForge Launcher"
|
||||||
tagline: "Ad blocking, custom themes, unlocked premium skins, and plugins."
|
tagline: "Ad-free experience, custom themes, unlocked premium skins, and plugins."
|
||||||
image:
|
image:
|
||||||
src: /logo.png
|
src: /logo.png
|
||||||
alt: BetterCurseForge
|
alt: BetterCurseForge
|
||||||
|
|
@ -18,30 +18,30 @@ hero:
|
||||||
|
|
||||||
features:
|
features:
|
||||||
- icon: 🚫
|
- icon: 🚫
|
||||||
title: Ad blocking
|
title: Complete Ad Removal
|
||||||
details: Ad requests are blocked at the network level, and CSS rules collapse the video ads, banners and empty containers that are left. The elements stay in the DOM, so React keeps working.
|
details: Multi-layer elimination (zero-ad CSS rules, network-level request blocking, and layout collapsing) removes all video ads, banners, and empty containers without disrupting React reconciliation.
|
||||||
- icon: 🎨
|
- icon: 🎨
|
||||||
title: Themes and free skins
|
title: Client Themes & Free Skins
|
||||||
details: Client themes show up in Settings -> Themes with live hover previews and a shortcut to the themes folder. The official premium skins are unlocked too.
|
details: Integrated directly into Settings -> Themes with live hover previews, theme folder shortcuts, and all native CurseForge Premium themes unlocked for free.
|
||||||
- icon: 🔄
|
- icon: 🔄
|
||||||
title: Auto-repatch after updates
|
title: Auto-Repatch & Smooth Updates
|
||||||
details: When the launcher updates, BetterCurseForge stops the unpatched copy from opening, shows a small splash window with progress, and repatches in a few seconds.
|
details: Survives launcher updates effortlessly. The active interceptor suppresses unpatched windows, and a sleek splash GUI displays live progress while repatching in seconds.
|
||||||
- icon: 🖥️
|
- icon: 🖥️
|
||||||
title: GUI and CLI
|
title: Modern GUI & CLI
|
||||||
details: A dark-themed desktop app with one-click actions, plus a command-line interface for scripting.
|
details: Includes an intuitive dark-themed desktop application with one-click actions, as well as a full command-line interface for power users.
|
||||||
- icon: 🧩
|
- icon: 🧩
|
||||||
title: Plugins
|
title: Plugin System
|
||||||
details: Write small JavaScript plugins that patch methods at runtime and keep their settings between restarts.
|
details: Extend launcher capabilities with lightweight JavaScript plugins using our runtime monkey-patcher and persistent settings API.
|
||||||
- icon: 🛡️
|
- icon: 🛡️
|
||||||
title: Backups and unpatching
|
title: Safe & 100% Reversible
|
||||||
details: Original files are backed up first (`app.asar.vanilla` and `CurseForge.exe.vanilla`), and you can restore stock CurseForge with one click.
|
details: Automatically creates clean vanilla backups (`app.asar.vanilla` and `CurseForge.exe.vanilla`). You can restore stock CurseForge at any time with a single click.
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="quickstart-section" style="margin-top: 3rem; text-align: center;">
|
<div class="quickstart-section" style="margin-top: 3rem; text-align: center;">
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
Download `BetterCurseForge.exe`, then open it for the GUI or patch from a terminal:
|
Download `BetterCurseForge.exe` and patch in one click:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Launch the desktop GUI:
|
# Launch the desktop GUI:
|
||||||
|
|
@ -57,15 +57,14 @@ BetterCurseForge.exe patch
|
||||||
|
|
||||||
## Why BetterCurseForge?
|
## Why BetterCurseForge?
|
||||||
|
|
||||||
CurseForge hosts Minecraft modpacks, World of Warcraft addons and other game mods, but the desktop app comes with ad containers, premium-only themes and telemetry.
|
CurseForge is the premier platform for Minecraft modpacks, World of Warcraft addons, and game mods, but the official desktop app is burdened with intrusive ad containers, locked premium themes, and heavy telemetry.
|
||||||
|
|
||||||
BetterCurseForge changes that:
|
**BetterCurseForge** restores a clean, fast, and customizable experience:
|
||||||
|
|
||||||
- **Native theme picker**: Client themes appear in **Settings -> Themes** next to the official ones, with live hover previews.
|
- **Seamless Native UI**: Client themes appear natively under **Settings -> Themes** alongside official themes, complete with real-time live hover previews.
|
||||||
- **Premium themes unlocked**: The official premium themes (*Pixelforge*, *Lifeforge*, *Fantasyforge*, *Spookyforge*) work without a subscription.
|
- **Unlocked Premium Themes**: Access all native CurseForge Premium themes (*Pixelforge*, *Lifeforge*, *Fantasyforge*, *Spookyforge*) without a subscription.
|
||||||
- **No ad columns**: Ad columns and sidebars are collapsed, so modpack grids use the full width of the window.
|
- **Zero-Ad Layouts**: Ad columns and sidebars are eliminated from the layout, letting modpack grids expand to fill your entire display.
|
||||||
- **Survives updates**: When CurseForge updates, BetterCurseForge detects it and reapplies the patch in a few seconds.
|
- **Automated Update Resistance**: Never worry about CurseForge updates breaking your setup—**Auto-Repatch** automatically detects updates and re-applies the patch in seconds.
|
||||||
- **Easy to undo**: Unpatch from the GUI or with `BetterCurseForge.exe unpatch` to get vanilla CurseForge back.
|
- **One-Click Reversible**: Easily unpatch anytime via the GUI or `BetterCurseForge.exe unpatch` to restore vanilla CurseForge.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue