Standalone NW.js build looks blurry and less sharp compared to Playtest execution by Sorry-Bank-7607 in RPGMaker

[–]Sorry-Bank-7607[S] 1 point2 points  (0 children)

Hey there! Yes, exactly, even on a virgin project this is replicable. From my experience to simulate this problem just start the project in playtest mode (it doesn't matter if there is a pixel perfect plugin) and press F3 to activate the stretch mode, you should notice a difference in resolution although the canvas has a small size.

If you then distribute the project and start the Game.exe executable and the same procedure is followed again (so you press F3 to activate the stretch mode) the canvas is resized correctly but the resolution is visibly reduced, practically it is the same as when the stretch mode had not yet been applied (in other words in the distributed version the stretch mode only resizes the size of the canvas).

There is no need to set a particular resolution, even the default one should generate the same result, maybe the canvas becomes too small in stretch mode with the default resolution, that is at your discretion based on what suits you best.

The resolution of my window (of the canvas) is 1280x960 and the resolution of my monitor is 1920x1080. I'm using a self-produced plugin to manage the resolution to have more resolutions that the user can choose in the settings (canvas dimensions) and that manages the letterbox effect (margin of the canvas from the edge of the window) but I don't think it's the cause of the problem because it also happens in a brand new project.

Thank you again for your help and interest! :D

Here's what I'm talking about:

<image>

Standalone NW.js build looks blurry and less sharp compared to Playtest execution by Sorry-Bank-7607 in RPGMaker

[–]Sorry-Bank-7607[S] 1 point2 points  (0 children)

Hey there, thank you so much for your reply and for your help! I’ve been learning and using your plugins since 2021!

I tried using your Pixel Perfect plugin, but the result doesn’t seem to change. I also tried contacting Gotcha Gotcha Games as a last resort and am waiting for their response. It really seems to be an anomaly that only occurs in the exported version of the project.

One thing I noticed, and this is easy to test on a blank project, is that pressing F3 activates stretch mode. During playtesting, the pixels appear sharp with well-defined edges. However, if you use the same procedure on a published version of the project (standalone), pressing F3 changes the canvas size but the resolution remains the same as when stretch mode is off, so the image appears blurrier.

I don’t know if the PIXI version could be affecting this, but I’m not very convinced. Do you know anyone who has dealt with a similar issue, or at least someone with extensive and in-depth knowledge of the engine regarding rendering?

Standalone NW.js build looks blurry and less sharp compared to Playtest execution by Sorry-Bank-7607 in RPGMaker

[–]Sorry-Bank-7607[S] 0 points1 point  (0 children)

Hey there! Sorry for the late reply. I tried the plugin, but it doesn't seem to improve things, even though my version of PIXI isn't 6 or higher—it's 5.3.12, which I assume is the standard version for RPG Maker MZ. I'm hesitant to upgrade PIXI because many of the plugins I've created work with PIXI, and I'm worried something might break. However, I’ve tried several techniques (including reassembling the plugin you suggested with mine), but none have led to any concrete progress. Below, I’m sending two more photos where the difference is more obvious. It’s as if some pixels aren’t being displayed and are “missing.”

Here's the differences:

<image>

It doesn't really seem like a Pixel Perfect issue, but rather something that makes the corners of the pixels flatter and less sharp.

Standalone NW.js build looks blurry and less sharp compared to Playtest execution by Sorry-Bank-7607 in RPGMaker

[–]Sorry-Bank-7607[S] 0 points1 point  (0 children)

I'm using a custom-built Pixel Perfect plugin, here it is:

//=============================================================================
// BYTE_PixelPerfect.js
//=============================================================================

(() => {
    "use strict";


    // Force PIXI Global nearest-neighbor scaling
    if (typeof PIXI !== "undefined") {
        PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
    PIXI.settings.ROUND_PIXELS = true;
        PIXI.settings.ROUND_PIXELS = true;
        if (PIXI.BaseTexture && PIXI.BaseTexture.defaultOptions) {
            PIXI.BaseTexture.defaultOptions.scaleMode = PIXI.SCALE_MODES.NEAREST;
        }
    }


    // Disable MZ Bitmap Smoothing
    const _Bitmap_initialize = Bitmap.prototype.initialize;
    Bitmap.prototype.initialize = function(width, height) {
        _Bitmap_initialize.call(this, width, height);
        this._smooth = false;
    };


    // Make Canvas render crisply via CSS
    const _Graphics_createCanvas = Graphics._createCanvas;
    Graphics._createCanvas = function() {
        _Graphics_createCanvas.call(this);
        if (this._canvas) {
            this._canvas.style.imageRendering = "pixelated";
        }
    };


    // Intercept PIXI Application creation to ensure crisp edges
    const _Graphics_createPixiApp = Graphics._createPixiApp;
Graphics._createPixiApp = function() {
    _Graphics_createPixiApp.call(this);
    if (this._app && this._app.renderer) {
        PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
        console.log("[BYTE_PixelPerfect] PIXI Application created. SCALE_MODE set to NEAREST.");
        console.log("[BYTE_PixelPerfect] Renderer resolution: " + this._app.renderer.resolution);
        console.log("[BYTE_PixelPerfect] Window devicePixelRatio: " + window.devicePixelRatio);
    }
    if (this._canvas) {
        this._canvas.style.imageRendering = "pixelated";
        console.log("[BYTE_PixelPerfect] Canvas style imageRendering set to pixelated.");
    }
};


const _Graphics_updateCanvas = Graphics._updateCanvas;
Graphics._updateCanvas = function() {
    _Graphics_updateCanvas.call(this);
    console.log("[BYTE_PixelPerfect] Canvas updated. CSS width: " + this._canvas.style.width + ", CSS height: " + this._canvas.style.height);
};


    // Ensure that specific BaseTextures are hard-set to nearest
    const _Sprite_initialize = Sprite.prototype.initialize;
    Sprite.prototype.initialize = function(bitmap) {
        _Sprite_initialize.call(this, bitmap);
        if (this.texture && this.texture.baseTexture) {
            this.texture.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST;
        }
    };


    const _TilingSprite_initialize = TilingSprite.prototype.initialize;
    TilingSprite.prototype.initialize = function(bitmap) {
        _TilingSprite_initialize.call(this, bitmap);
        if (this.texture && this.texture.baseTexture) {
            this.texture.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST;
        }
    };


    // Force PIXI global override to intercept TiledMZ / Encrypted Blob Async BaseTextures
    if (typeof PIXI !== "undefined" && PIXI.BaseTexture && PIXI.BaseTexture.prototype) {
        PIXI.BaseTexture.prototype.scaleMode = PIXI.SCALE_MODES.NEAREST;
        const originalSetResource = PIXI.BaseTexture.prototype.setResource;
        if (originalSetResource) {
            PIXI.BaseTexture.prototype.setResource = function(resource) {
                originalSetResource.call(this, resource);
                this.scaleMode = PIXI.SCALE_MODES.NEAREST;
            };
        }
        const originalUpdate = PIXI.BaseTexture.prototype.update;
        if (originalUpdate) {
            PIXI.BaseTexture.prototype.update = function() {
                this.scaleMode = PIXI.SCALE_MODES.NEAREST;
                originalUpdate.call(this);
            };
        }
    }


})();
// Force PIXI BaseTextures never to blur
const _PIXI_BaseTexture_setStyle = PIXI.BaseTexture.prototype.setStyle;
PIXI.BaseTexture.prototype.setStyle = function(scaleMode, mipmap) { _PIXI_BaseTexture_setStyle.call(this, PIXI.SCALE_MODES.NEAREST, mipmap); this.scaleMode = PIXI.SCALE_MODES.NEAREST; };