mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
🆙 Small fixing alphablend
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import './pixiPatch';
|
||||||
|
|
||||||
import { GetConfiguration } from '@nitrots/nitro-renderer';
|
import { GetConfiguration } from '@nitrots/nitro-renderer';
|
||||||
import JSON5 from 'json5';
|
import JSON5 from 'json5';
|
||||||
import { configFileUrl, getClientMode, installSecureFetch } from './secure-assets';
|
import { configFileUrl, getClientMode, installSecureFetch } from './secure-assets';
|
||||||
|
|||||||
@@ -8,13 +8,8 @@ export const LayoutRoomPreviewerView: FC<{
|
|||||||
{
|
{
|
||||||
const { roomPreviewer = null, height = 0 } = props;
|
const { roomPreviewer = null, height = 0 } = props;
|
||||||
const elementRef = useRef<HTMLDivElement>(null);
|
const elementRef = useRef<HTMLDivElement>(null);
|
||||||
// Latch that disables further renders once Pixi throws inside this
|
const renderFailuresRef = useRef(0);
|
||||||
// previewer. The crash (e.g. blackhole furni's filter chain that
|
const MAX_RENDER_FAILURES = 6;
|
||||||
// accesses .alphaMode on a null texture) repeats every animation
|
|
||||||
// frame as long as the ticker keeps firing, flooding the console
|
|
||||||
// and locking the catalog. One catch and we stop trying for the
|
|
||||||
// lifetime of this previewer instance.
|
|
||||||
const renderFailedRef = useRef(false);
|
|
||||||
|
|
||||||
const onClick = (event: MouseEvent<HTMLDivElement>) =>
|
const onClick = (event: MouseEvent<HTMLDivElement>) =>
|
||||||
{
|
{
|
||||||
@@ -28,14 +23,24 @@ export const LayoutRoomPreviewerView: FC<{
|
|||||||
{
|
{
|
||||||
if(!elementRef) return;
|
if(!elementRef) return;
|
||||||
|
|
||||||
renderFailedRef.current = false;
|
renderFailuresRef.current = 0;
|
||||||
|
|
||||||
const width = elementRef.current.parentElement.clientWidth;
|
const width = elementRef.current.parentElement.clientWidth;
|
||||||
const texture = TextureUtils.createRenderTexture(width, height);
|
const texture = TextureUtils.createRenderTexture(width, height);
|
||||||
|
|
||||||
|
const noteFailure = (label: string, error: unknown) =>
|
||||||
|
{
|
||||||
|
renderFailuresRef.current += 1;
|
||||||
|
|
||||||
|
if(renderFailuresRef.current >= MAX_RENDER_FAILURES)
|
||||||
|
{
|
||||||
|
NitroLogger.error(`LayoutRoomPreviewerView ${ label } failed ${ renderFailuresRef.current } times; disabling further renders for this preview`, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const paintToDOM = () =>
|
const paintToDOM = () =>
|
||||||
{
|
{
|
||||||
if(renderFailedRef.current) return;
|
if(renderFailuresRef.current >= MAX_RENDER_FAILURES) return;
|
||||||
if(!roomPreviewer || !elementRef.current) return;
|
if(!roomPreviewer || !elementRef.current) return;
|
||||||
|
|
||||||
const renderingCanvas = roomPreviewer.getRenderingCanvas();
|
const renderingCanvas = roomPreviewer.getRenderingCanvas();
|
||||||
@@ -57,17 +62,17 @@ export const LayoutRoomPreviewerView: FC<{
|
|||||||
canvas.height = 0;
|
canvas.height = 0;
|
||||||
|
|
||||||
elementRef.current.style.backgroundImage = `url(${ base64 })`;
|
elementRef.current.style.backgroundImage = `url(${ base64 })`;
|
||||||
|
renderFailuresRef.current = 0;
|
||||||
}
|
}
|
||||||
catch(error)
|
catch(error)
|
||||||
{
|
{
|
||||||
renderFailedRef.current = true;
|
noteFailure('paint', error);
|
||||||
NitroLogger.error('LayoutRoomPreviewerView paint failed; disabling further renders for this preview', error);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const update = (ticker: NitroTicker) =>
|
const update = (ticker: NitroTicker) =>
|
||||||
{
|
{
|
||||||
if(renderFailedRef.current) return;
|
if(renderFailuresRef.current >= MAX_RENDER_FAILURES) return;
|
||||||
if(!roomPreviewer || !elementRef.current) return;
|
if(!roomPreviewer || !elementRef.current) return;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -76,8 +81,7 @@ export const LayoutRoomPreviewerView: FC<{
|
|||||||
}
|
}
|
||||||
catch(error)
|
catch(error)
|
||||||
{
|
{
|
||||||
renderFailedRef.current = true;
|
noteFailure('update', error);
|
||||||
NitroLogger.error('LayoutRoomPreviewerView update failed; disabling further renders for this preview', error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
|||||||
{ LocalizeText('catalog.pets.back.breeds') }
|
{ LocalizeText('catalog.pets.back.breeds') }
|
||||||
</button> }
|
</button> }
|
||||||
</div>
|
</div>
|
||||||
<div className={ colorsShowing ? 'nitro-catalog-classic-color-swatches flex flex-wrap gap-1 p-2 overflow-auto' : 'grid grid-cols-6 gap-1' }>
|
<div className={ colorsShowing ? 'nitro-catalog-classic-color-swatches flex flex-wrap gap-1 p-2 overflow-auto' : 'nitro-catalog-classic-pet-breeds flex flex-wrap gap-1 p-1 overflow-auto' }>
|
||||||
{ !colorsShowing && (sellablePalettes.length > 0) && sellablePalettes.map((palette, index) => (
|
{ !colorsShowing && (sellablePalettes.length > 0) && sellablePalettes.map((palette, index) => (
|
||||||
<LayoutGridItem
|
<LayoutGridItem
|
||||||
key={ index }
|
key={ index }
|
||||||
|
|||||||
@@ -12,19 +12,10 @@
|
|||||||
--catalog-swf-select-outer: #82d1ed;
|
--catalog-swf-select-outer: #82d1ed;
|
||||||
--catalog-swf-bc: #ff8d00;
|
--catalog-swf-bc: #ff8d00;
|
||||||
--catalog-swf-bc-outer: #ffb53c;
|
--catalog-swf-bc-outer: #ffb53c;
|
||||||
/* Light gray secondary button - cropped from catalog_skin1.png
|
|
||||||
at (10, 190, 25x22). Drives the gift button "Cadeau", the
|
|
||||||
preview-room control button and the generic .nitro-catalog-swf-
|
|
||||||
button via border-image-slice 3 3 3 3 fill. */
|
|
||||||
--habbo-slice-button-default: url("../../assets/images/catalog/buttons/btn_secondary.png");
|
--habbo-slice-button-default: url("../../assets/images/catalog/buttons/btn_secondary.png");
|
||||||
--habbo-slice-button-hover: url("../../assets/images/catalog/buttons/btn_secondary_hover.png");
|
--habbo-slice-button-hover: url("../../assets/images/catalog/buttons/btn_secondary_hover.png");
|
||||||
--habbo-slice-button-pressed: url("../../assets/images/catalog/buttons/btn_secondary_pressed.png");
|
--habbo-slice-button-pressed: url("../../assets/images/catalog/buttons/btn_secondary_pressed.png");
|
||||||
--habbo-slice-button-disabled: url("../../assets/images/catalog/buttons/btn_secondary_disabled.png");
|
--habbo-slice-button-disabled: url("../../assets/images/catalog/buttons/btn_secondary_disabled.png");
|
||||||
/* Classic Habbo "Osta!" Buy button - cropped from catalog_skin3.png
|
|
||||||
yellow band. The historical name says "green" but the user's
|
|
||||||
skin sheet ships yellow for the action colour, so that's what
|
|
||||||
we paint. The 27x34 sprite border-image-slices nicely at 6px
|
|
||||||
since the rounded corner is ~5px. */
|
|
||||||
--habbo-slice-button-buy: url("../../assets/images/catalog/buttons/buy.png");
|
--habbo-slice-button-buy: url("../../assets/images/catalog/buttons/buy.png");
|
||||||
--habbo-slice-button-large: url("../../assets/images/catalog/buttons/buy.png");
|
--habbo-slice-button-large: url("../../assets/images/catalog/buttons/buy.png");
|
||||||
--habbo-slice-button-large-hover: url("../../assets/images/catalog/buttons/buy_hover.png");
|
--habbo-slice-button-large-hover: url("../../assets/images/catalog/buttons/buy_hover.png");
|
||||||
@@ -48,9 +39,6 @@
|
|||||||
--habbo-stepper-minus-hover: url("../../assets/images/catalog/buttons/minus_hover.png");
|
--habbo-stepper-minus-hover: url("../../assets/images/catalog/buttons/minus_hover.png");
|
||||||
--habbo-stepper-minus-pressed: url("../../assets/images/catalog/buttons/minus_pressed.png");
|
--habbo-stepper-minus-pressed: url("../../assets/images/catalog/buttons/minus_pressed.png");
|
||||||
--habbo-stepper-minus-disabled: url("../../assets/images/catalog/buttons/minus_disabled.png");
|
--habbo-stepper-minus-disabled: url("../../assets/images/catalog/buttons/minus_disabled.png");
|
||||||
/* Scrollbar sprites cropped from catalog_skin1.png. The single-piece
|
|
||||||
thumb has caps + grip baked into one 17x34 image - stretch it
|
|
||||||
full-height with background-size: 17px 100%. */
|
|
||||||
--habbo-scrollbar-up: url("../../assets/images/catalog/scrollbar/scroll_v_up.png");
|
--habbo-scrollbar-up: url("../../assets/images/catalog/scrollbar/scroll_v_up.png");
|
||||||
--habbo-scrollbar-up-pressed: url("../../assets/images/catalog/scrollbar/scroll_v_up_pressed.png");
|
--habbo-scrollbar-up-pressed: url("../../assets/images/catalog/scrollbar/scroll_v_up_pressed.png");
|
||||||
--habbo-scrollbar-down: url("../../assets/images/catalog/scrollbar/scroll_v_down.png");
|
--habbo-scrollbar-down: url("../../assets/images/catalog/scrollbar/scroll_v_down.png");
|
||||||
@@ -768,6 +756,16 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Default-3x3 layout: .offer-info is rendered but hidden via the
|
||||||
|
display: none rule below, so the panel reserved the full width
|
||||||
|
while only the 360px preview was visible (empty strip on the
|
||||||
|
right). Center the preview inside the panel instead so the gap
|
||||||
|
becomes symmetric padding on both sides. Color-grouping doesn't
|
||||||
|
render .offer-info so its panel keeps the existing layout. */
|
||||||
|
.nitro-catalog-classic-offer-panel:has(> .nitro-catalog-classic-offer-info) {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.nitro-catalog-classic-offer-preview {
|
.nitro-catalog-classic-offer-preview {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -879,11 +877,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nitro-catalog-classic-window .layout-grid-item {
|
.nitro-catalog-classic-window .layout-grid-item {
|
||||||
/* Let the tile flex to whatever min/max width the AutoGrid sets
|
|
||||||
via repeat(auto-fill, minmax(N, 1fr)) - hard-pinning 53x74 was
|
|
||||||
overriding the layout's columnMinWidth prop, so the row count
|
|
||||||
never changed when we reduced it. Width is now 100% of the
|
|
||||||
column cell, height tracks --nitro-grid-column-min-height. */
|
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
height: var(--nitro-grid-column-min-height, 70px) !important;
|
height: var(--nitro-grid-column-min-height, 70px) !important;
|
||||||
min-width: 0 !important;
|
min-width: 0 !important;
|
||||||
@@ -895,14 +888,17 @@
|
|||||||
overflow: visible !important;
|
overflow: visible !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Furni tiles drive their look from the icon image and need a clear
|
|
||||||
background. Color-grouping swatches use itemHighlight (.has-highlight)
|
|
||||||
to ask LayoutGridItem for a solid colour via inline backgroundColor -
|
|
||||||
keep the transparent override off those so the swatch is visible. */
|
|
||||||
.nitro-catalog-classic-window .layout-grid-item:not(.has-highlight) {
|
.nitro-catalog-classic-window .layout-grid-item:not(.has-highlight) {
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nitro-catalog-classic-window .nitro-catalog-classic-pet-breeds .layout-grid-item {
|
||||||
|
width: 84px !important;
|
||||||
|
min-width: 84px !important;
|
||||||
|
height: 74px !important;
|
||||||
|
min-height: 74px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.nitro-catalog-classic-window .layout-grid-item:hover {
|
.nitro-catalog-classic-window .layout-grid-item:hover {
|
||||||
background-image: none !important;
|
background-image: none !important;
|
||||||
box-shadow: inset 0 0 0 1px #a1a19b !important;
|
box-shadow: inset 0 0 0 1px #a1a19b !important;
|
||||||
@@ -916,12 +912,6 @@
|
|||||||
inset -2px -2px 0 #ecece4 !important;
|
inset -2px -2px 0 #ecece4 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Habbo-classic colour swatches: small chip with a 1px dark border
|
|
||||||
and a subtle inner highlight so light tones still read as buttons.
|
|
||||||
Hover lifts the border; the selected swatch is "pressed" with a
|
|
||||||
sunken inner shadow and a bright cyan ring matching the catalog
|
|
||||||
selection accent. The cream inset from the generic .is-active rule
|
|
||||||
above would wash out the swatch colour, so we replace it here. */
|
|
||||||
.nitro-catalog-classic-window .layout-grid-item.has-highlight {
|
.nitro-catalog-classic-window .layout-grid-item.has-highlight {
|
||||||
width: 26px !important;
|
width: 26px !important;
|
||||||
height: 26px !important;
|
height: 26px !important;
|
||||||
@@ -985,18 +975,10 @@
|
|||||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.75);
|
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When the tile shows a full-tile bot/pet avatar (instead of a small
|
|
||||||
icon), pin the price strip to the bottom of the tile and give it a
|
|
||||||
translucent backdrop so it doesn't overlap with the avatar body. */
|
|
||||||
.nitro-catalog-classic-grid .layout-grid-item:has(.avatar-image) .nitro-catalog-classic-grid-price,
|
.nitro-catalog-classic-grid .layout-grid-item:has(.avatar-image) .nitro-catalog-classic-grid-price,
|
||||||
.nitro-catalog-classic-grid .layout-grid-item:has(> .avatar-image) > .nitro-catalog-classic-grid-price,
|
.nitro-catalog-classic-grid .layout-grid-item:has(> .avatar-image) > .nitro-catalog-classic-grid-price,
|
||||||
.nitro-catalog-classic-grid .avatar-image ~ .nitro-catalog-classic-grid-price {
|
.nitro-catalog-classic-grid .avatar-image ~ .nitro-catalog-classic-grid-price {
|
||||||
top: auto !important;
|
top: auto !important;
|
||||||
/* Re-anchor horizontally too: the parent rule's left: 2px /
|
|
||||||
right: 2px combined with content-sized inner flex was visually
|
|
||||||
parking the pill at the left side of the tile. Center it via
|
|
||||||
explicit left/right + transform so it lands smack in the
|
|
||||||
middle regardless of inner content width. */
|
|
||||||
left: 50% !important;
|
left: 50% !important;
|
||||||
right: auto !important;
|
right: auto !important;
|
||||||
bottom: 4px !important;
|
bottom: 4px !important;
|
||||||
@@ -1014,10 +996,6 @@
|
|||||||
z-index: 5 !important;
|
z-index: 5 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tighten the price entry inside the avatar-tile pill so the number
|
|
||||||
and currency icon center on the same baseline (the global
|
|
||||||
.grid-price-entry height: 13px clipped the 15px wallet icon and
|
|
||||||
pushed it visually below the number). */
|
|
||||||
.nitro-catalog-classic-grid .layout-grid-item:has(.avatar-image) .nitro-catalog-classic-grid-price-entry,
|
.nitro-catalog-classic-grid .layout-grid-item:has(.avatar-image) .nitro-catalog-classic-grid-price-entry,
|
||||||
.nitro-catalog-classic-grid .avatar-image ~ .nitro-catalog-classic-grid-price .nitro-catalog-classic-grid-price-entry {
|
.nitro-catalog-classic-grid .avatar-image ~ .nitro-catalog-classic-grid-price .nitro-catalog-classic-grid-price-entry {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
@@ -1070,8 +1048,6 @@
|
|||||||
.nitro-catalog-classic-price-row {
|
.nitro-catalog-classic-price-row {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
/* Anchored from the bottom so the Aantal/Prezzo row sits just
|
|
||||||
above the Cadeau/Koop buttons regardless of layout height. */
|
|
||||||
bottom: 38px;
|
bottom: 38px;
|
||||||
width: 360px;
|
width: 360px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
@@ -1089,8 +1065,6 @@
|
|||||||
|
|
||||||
.nitro-catalog-classic-total-price-slot {
|
.nitro-catalog-classic-total-price-slot {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
/* Anchored to the right of the now-100% wide price row so the
|
|
||||||
Prezzo + amount stays flush with the right edge of the panel. */
|
|
||||||
right: 2px;
|
right: 2px;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: auto;
|
width: auto;
|
||||||
@@ -1113,9 +1087,6 @@
|
|||||||
.nitro-catalog-classic-purchase-row {
|
.nitro-catalog-classic-purchase-row {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
/* Anchored to the bottom of the panel with a 4px breathing strip
|
|
||||||
so the Cadeau / Koop buttons stay flush at the bottom of the
|
|
||||||
window no matter how tall the catalog is. */
|
|
||||||
bottom: 4px;
|
bottom: 4px;
|
||||||
width: 360px;
|
width: 360px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
@@ -1129,9 +1100,6 @@
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 10px !important;
|
gap: 10px !important;
|
||||||
/* Fill the now-100% wide purchase row instead of staying pinned at
|
|
||||||
330px (which used to match the old 360px column - 15px each
|
|
||||||
side). */
|
|
||||||
width: auto;
|
width: auto;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
@@ -1191,13 +1159,6 @@
|
|||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Buy / Gift buttons - pure CSS. border-image-slicing the bitmap
|
|
||||||
sprites produced thin highlight/shadow stripes at the top and
|
|
||||||
bottom because the source rounded corners are ~5-6px tall but the
|
|
||||||
buttons render at 22-24px, so the slice rows stretched into a
|
|
||||||
visible band. CSS gradients give a crisp pixel-art classic-habbo
|
|
||||||
look without those artefacts. */
|
|
||||||
|
|
||||||
.nitro-catalog-classic-window .nitro-catalog-swf-buy-button {
|
.nitro-catalog-classic-window .nitro-catalog-swf-buy-button {
|
||||||
width: 160px !important;
|
width: 160px !important;
|
||||||
min-width: 160px !important;
|
min-width: 160px !important;
|
||||||
@@ -1207,8 +1168,6 @@
|
|||||||
border-radius: 4px !important;
|
border-radius: 4px !important;
|
||||||
border-image: none !important;
|
border-image: none !important;
|
||||||
border-image-source: none !important;
|
border-image-source: none !important;
|
||||||
/* Yellow body with the same #f0a318 / #ffd54d tones as the
|
|
||||||
skin3-yellow Buy sprite. */
|
|
||||||
background:
|
background:
|
||||||
linear-gradient(180deg, #ffe66b 0%, #ffc828 45%, #f0a318 100%) !important;
|
linear-gradient(180deg, #ffe66b 0%, #ffc828 45%, #f0a318 100%) !important;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
@@ -1235,9 +1194,6 @@
|
|||||||
|
|
||||||
.nitro-catalog-classic-window .nitro-catalog-swf-buy-button.pointer-events-none,
|
.nitro-catalog-classic-window .nitro-catalog-swf-buy-button.pointer-events-none,
|
||||||
.nitro-catalog-classic-window .nitro-catalog-swf-buy-button:disabled {
|
.nitro-catalog-classic-window .nitro-catalog-swf-buy-button:disabled {
|
||||||
/* Stay yellow when disabled - the user wants the action colour
|
|
||||||
to be recognisable regardless of state. Drop opacity + flip
|
|
||||||
the cursor so it still reads as non-interactive. */
|
|
||||||
background:
|
background:
|
||||||
linear-gradient(180deg, #ffe66b 0%, #ffc828 45%, #f0a318 100%) !important;
|
linear-gradient(180deg, #ffe66b 0%, #ffc828 45%, #f0a318 100%) !important;
|
||||||
color: #4a2b00 !important;
|
color: #4a2b00 !important;
|
||||||
@@ -1255,7 +1211,6 @@
|
|||||||
border-radius: 4px !important;
|
border-radius: 4px !important;
|
||||||
border-image: none !important;
|
border-image: none !important;
|
||||||
border-image-source: none !important;
|
border-image-source: none !important;
|
||||||
/* Cream / light-gray body matching the catalog cardstock. */
|
|
||||||
background:
|
background:
|
||||||
linear-gradient(180deg, #ececec 0%, #cfcfc4 100%) !important;
|
linear-gradient(180deg, #ececec 0%, #cfcfc4 100%) !important;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
@@ -1288,19 +1243,12 @@
|
|||||||
text-shadow: none !important;
|
text-shadow: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pet purchase card lives in a tight flex row alongside the price,
|
|
||||||
so the main 160px Buy button doesn't fit. Shrink it down here. */
|
|
||||||
.nitro-catalog-classic-pet-card .nitro-catalog-swf-buy-button {
|
.nitro-catalog-classic-pet-card .nitro-catalog-swf-buy-button {
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
min-width: 0 !important;
|
min-width: 0 !important;
|
||||||
padding: 0 14px !important;
|
padding: 0 14px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All catalog grids must scroll vertically only - horizontal overflow
|
|
||||||
produces a stray horizontal scrollbar at the bottom of the items
|
|
||||||
strip on narrow columns (e.g. guild_furni). minmax(N, 1fr) usually
|
|
||||||
contains content but the safety net stops any odd item from
|
|
||||||
triggering a horizontal bar. */
|
|
||||||
.nitro-catalog-classic-window .layout-grid,
|
.nitro-catalog-classic-window .layout-grid,
|
||||||
.nitro-catalog-classic-window [class*="grid-cols-["] {
|
.nitro-catalog-classic-window [class*="grid-cols-["] {
|
||||||
overflow-x: hidden !important;
|
overflow-x: hidden !important;
|
||||||
@@ -1347,8 +1295,6 @@
|
|||||||
image-rendering: pixelated !important;
|
image-rendering: pixelated !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* react-icons FaMinus/FaPlus glyphs ride inside these buttons; hide
|
|
||||||
them - the sprite already contains the +/- mark. */
|
|
||||||
.nitro-catalog-classic-window button.nitro-catalog-swf-spinner-button svg {
|
.nitro-catalog-classic-window button.nitro-catalog-swf-spinner-button svg {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
@@ -1444,9 +1390,6 @@
|
|||||||
min-width: 25px;
|
min-width: 25px;
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
/* font-size: 0 was killing the SVG: react-icons emits
|
|
||||||
<svg width="1em" height="1em">, so 0em -> 0x0. Use a real
|
|
||||||
font-size and pin the SVG to explicit pixels below. */
|
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
line-height: 1 !important;
|
line-height: 1 !important;
|
||||||
display: inline-flex !important;
|
display: inline-flex !important;
|
||||||
@@ -1473,13 +1416,6 @@
|
|||||||
right: 6px;
|
right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bulletproof override for the rotate/state buttons. The shared SWF
|
|
||||||
button rule above lays a transparent body + border-image skin on
|
|
||||||
top, which works only when the catalog/buttons/btn_secondary*.png
|
|
||||||
sprites resolve - if they're missing the button renders 0x0
|
|
||||||
invisible. Pin the box and paint a visible gradient + outline so
|
|
||||||
the controls are always discoverable, and force z-index above the
|
|
||||||
room-previewer DIV so they sit on top of the rendered scene. */
|
|
||||||
.nitro-catalog-classic-window button.nitro-catalog-classic-preview-btn {
|
.nitro-catalog-classic-window button.nitro-catalog-classic-preview-btn {
|
||||||
width: 28px !important;
|
width: 28px !important;
|
||||||
height: 26px !important;
|
height: 26px !important;
|
||||||
@@ -1520,12 +1456,6 @@
|
|||||||
height: 17px;
|
height: 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Classic catalog scrollbar (pure CSS, no sprites) =====
|
|
||||||
Drew this with CSS gradients instead of stretching the 17x34
|
|
||||||
skin1 thumb sprite. The sprite version pixelated into visible
|
|
||||||
horizontal bands on tall scroll areas because every source row
|
|
||||||
stretched 5-10x. CSS gradients stay crisp at any height. */
|
|
||||||
|
|
||||||
.nitro-catalog-classic-window * {
|
.nitro-catalog-classic-window * {
|
||||||
scrollbar-color: auto !important;
|
scrollbar-color: auto !important;
|
||||||
scrollbar-width: auto;
|
scrollbar-width: auto;
|
||||||
@@ -1544,10 +1474,6 @@
|
|||||||
border: 0 !important;
|
border: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Habbo thumb: symmetric light-edges -> darker-middle gradient (the
|
|
||||||
"pinched in the middle" look of the classic Ubuntu scrollbar),
|
|
||||||
1px near-black outline, three central grip lines via SVG centered
|
|
||||||
no-repeat. */
|
|
||||||
.nitro-catalog-classic-window *::-webkit-scrollbar-thumb {
|
.nitro-catalog-classic-window *::-webkit-scrollbar-thumb {
|
||||||
min-height: 28px !important;
|
min-height: 28px !important;
|
||||||
border: 1px solid #2a2a26 !important;
|
border: 1px solid #2a2a26 !important;
|
||||||
@@ -1577,8 +1503,6 @@
|
|||||||
inset 0 -1px 0 rgba(255, 255, 255, 0.25) !important;
|
inset 0 -1px 0 rgba(255, 255, 255, 0.25) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Arrow buttons: cream cap with a 1px black outline + dark inset
|
|
||||||
chevron. SVG glyphs so they stay crisp at any zoom. */
|
|
||||||
.nitro-catalog-classic-window *::-webkit-scrollbar-button:single-button:vertical:decrement {
|
.nitro-catalog-classic-window *::-webkit-scrollbar-button:single-button:vertical:decrement {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
width: 17px !important;
|
width: 17px !important;
|
||||||
@@ -1680,6 +1604,20 @@
|
|||||||
padding: 6px !important;
|
padding: 6px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile: drop the per-page welcome row (image + localization
|
||||||
|
blurb shown when no offer is selected). On a narrow viewport
|
||||||
|
it eats most of the visible space and pushes the actual grid
|
||||||
|
off-screen. Hide it and also collapse the surrounding
|
||||||
|
product-view (otherwise its 240px height reservation stays
|
||||||
|
and leaves a blank strip above the grid). */
|
||||||
|
.nitro-catalog-classic-welcome {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nitro-catalog-classic-product-view:has(> .nitro-catalog-classic-welcome) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
.nitro-catalog-classic-stage,
|
.nitro-catalog-classic-stage,
|
||||||
.nitro-catalog-classic-stage.is-navigation-hidden {
|
.nitro-catalog-classic-stage.is-navigation-hidden {
|
||||||
grid-template-columns: minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
actly once, idempotent across HMR reloads.
|
||||||
|
*/
|
||||||
|
import * as PIXI from 'pixi.js';
|
||||||
|
|
||||||
|
type AnyFn = (...args: unknown[]) => unknown;
|
||||||
|
|
||||||
|
interface MethodHost {
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
__nitroPixiBatcherPatched__?: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NULL_TEXTURE_MARKERS = /alphaMode|reading 'uid'|reading 'destroyed'|reading 'source'/;
|
||||||
|
|
||||||
|
const isNullTextureCrash = (err: unknown): boolean =>
|
||||||
|
{
|
||||||
|
if(!(err instanceof TypeError)) return false;
|
||||||
|
return NULL_TEXTURE_MARKERS.test(err.message ?? '');
|
||||||
|
};
|
||||||
|
|
||||||
|
const guardMethod = (proto: MethodHost, methodName: string, label: string): boolean =>
|
||||||
|
{
|
||||||
|
const original = proto[methodName];
|
||||||
|
if(typeof original !== 'function') return false;
|
||||||
|
if((original as { __nitroGuarded__?: boolean }).__nitroGuarded__) return false;
|
||||||
|
|
||||||
|
const guarded = function(this: unknown, ...args: unknown[])
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (original as AnyFn).apply(this, args);
|
||||||
|
}
|
||||||
|
catch(err)
|
||||||
|
{
|
||||||
|
if(isNullTextureCrash(err)) return undefined;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(guarded as { __nitroGuarded__?: boolean }).__nitroGuarded__ = true;
|
||||||
|
proto[methodName] = guarded;
|
||||||
|
|
||||||
|
|
||||||
|
console.info(`[NitroPixiPatch] guarded ${ label }.prototype.${ methodName } against null textureSource`);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const installPatch = (): void =>
|
||||||
|
{
|
||||||
|
if(typeof window === 'undefined') return;
|
||||||
|
if(window.__nitroPixiBatcherPatched__) return;
|
||||||
|
|
||||||
|
const candidates: Array<[string, unknown]> = [
|
||||||
|
[ 'DefaultBatcher', (PIXI as Record<string, unknown>).DefaultBatcher ],
|
||||||
|
[ 'Batcher', (PIXI as Record<string, unknown>).Batcher ]
|
||||||
|
];
|
||||||
|
|
||||||
|
let patched = false;
|
||||||
|
|
||||||
|
for(const [ name, ctor ] of candidates)
|
||||||
|
{
|
||||||
|
const proto = (ctor as { prototype?: MethodHost } | undefined)?.prototype;
|
||||||
|
if(!proto) continue;
|
||||||
|
|
||||||
|
if(guardMethod(proto, 'break', name)) patched = true;
|
||||||
|
|
||||||
|
if(guardMethod(proto, 'checkAndUpdateTexture', name)) patched = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.__nitroPixiBatcherPatched__ = patched;
|
||||||
|
|
||||||
|
if(!patched)
|
||||||
|
{
|
||||||
|
|
||||||
|
console.warn('[NitroPixiPatch] could not locate Batcher.prototype methods - is pixi.js export shape unchanged?');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
installPatch();
|
||||||
Reference in New Issue
Block a user