diff --git a/src/app/WardrobePage/OutfitControls.js b/src/app/WardrobePage/OutfitControls.js
index 814d77b..8265192 100644
--- a/src/app/WardrobePage/OutfitControls.js
+++ b/src/app/WardrobePage/OutfitControls.js
@@ -43,6 +43,7 @@ import { loadImage, useLocalStorage } from "../util";
import useCurrentUser from "../components/useCurrentUser";
import useOutfitAppearance from "../components/useOutfitAppearance";
import OutfitKnownGlitchesBadge from "./OutfitKnownGlitchesBadge";
+import usePreferArchive from "../components/usePreferArchive";
/**
* OutfitControls is the set of controls layered over the outfit preview, to
@@ -500,28 +501,56 @@ function SettingsButton({ onLockFocus, onUnlockFocus }) {
function HiResModeSetting() {
const [hiResMode, setHiResMode] = useLocalStorage("DTIHiResMode", false);
+ const [preferArchive, setPreferArchive] = usePreferArchive();
return (
-
-
-
-
- Hi-res mode (SVG)
-
-
- Crisper at higher resolutions, but not always accurate
-
-
-
- setHiResMode(e.target.checked)}
- />
-
-
+
+
+
+
+
+ Hi-res mode (SVG)
+
+
+ Crisper at higher resolutions, but not always accurate
+
+
+
+ setHiResMode(e.target.checked)}
+ />
+
+
+
+
+
+
+
+ Use DTI's image archive
+
+
+ Turn this on when images.neopets.com is slow!
+
+
+
+ setPreferArchive(e.target.checked)}
+ />
+
+
+
);
}
@@ -585,6 +614,7 @@ function ControlButton({ icon, "aria-label": ariaLabel, ...props }) {
*/
function useDownloadableImage(visibleLayers) {
const [hiResMode] = useLocalStorage("DTIHiResMode", false);
+ const [preferArchive] = usePreferArchive();
const [downloadImageUrl, setDownloadImageUrl] = React.useState(null);
const [preparedForLayerIds, setPreparedForLayerIds] = React.useState([]);
@@ -611,6 +641,7 @@ function useDownloadableImage(visibleLayers) {
const imagePromises = visibleLayers.map((layer) =>
loadImage(getBestImageUrlForLayer(layer, { hiResMode }), {
crossOrigin: "anonymous",
+ preferArchive,
})
);
@@ -644,7 +675,7 @@ function useDownloadableImage(visibleLayers) {
);
setDownloadImageUrl(canvas.toDataURL("image/png"));
setPreparedForLayerIds(layerIds);
- }, [preparedForLayerIds, visibleLayers, toast, hiResMode]);
+ }, [preparedForLayerIds, visibleLayers, toast, hiResMode, preferArchive]);
return [downloadImageUrl, prepareDownload];
}
diff --git a/src/app/components/ItemCard.js b/src/app/components/ItemCard.js
index faa0461..b87237e 100644
--- a/src/app/components/ItemCard.js
+++ b/src/app/components/ItemCard.js
@@ -21,6 +21,7 @@ import Link from "next/link";
import SquareItemCard from "./SquareItemCard";
import { safeImageUrl, useCommonStyles } from "../util";
+import usePreferArchive from "./usePreferArchive";
function ItemCard({ item, badges, variant = "list", ...props }) {
const { brightBackground } = useCommonStyles();
@@ -105,6 +106,7 @@ export function ItemThumbnail({
focusSelector,
...props
}) {
+ const [preferArchive] = usePreferArchive();
const theme = useTheme();
const borderColor = useColorModeValue(
@@ -170,7 +172,7 @@ export function ItemThumbnail({
as="img"
width="100%"
height="100%"
- src={safeImageUrl(item.thumbnailUrl)}
+ src={safeImageUrl(item.thumbnailUrl, { preferArchive })}
alt={`Thumbnail art for ${item.name}`}
/>
)}
diff --git a/src/app/components/OutfitMovieLayer.js b/src/app/components/OutfitMovieLayer.js
index ac8c06e..81248cb 100644
--- a/src/app/components/OutfitMovieLayer.js
+++ b/src/app/components/OutfitMovieLayer.js
@@ -3,6 +3,7 @@ import LRU from "lru-cache";
import { Box, Grid, useToast } from "@chakra-ui/react";
import { loadImage, logAndCapture, safeImageUrl } from "../util";
+import usePreferArchive from "./usePreferArchive";
// Import EaselJS and TweenJS directly into the `window` object! The bundled
// scripts are built to attach themselves to `window.createjs`, and
@@ -24,6 +25,7 @@ function OutfitMovieLayer({
onLowFps = null,
canvasProps = {},
}) {
+ const [preferArchive] = usePreferArchive();
const [stage, setStage] = React.useState(null);
const [library, setLibrary] = React.useState(null);
const [movieClip, setMovieClip] = React.useState(null);
@@ -129,7 +131,7 @@ function OutfitMovieLayer({
React.useEffect(() => {
let canceled = false;
- const movieLibraryPromise = loadMovieLibrary(libraryUrl);
+ const movieLibraryPromise = loadMovieLibrary(libraryUrl, { preferArchive });
movieLibraryPromise
.then((library) => {
if (canceled) {
@@ -154,7 +156,7 @@ function OutfitMovieLayer({
setLibrary(null);
setMovieClip(null);
};
- }, [libraryUrl, onError]);
+ }, [libraryUrl, preferArchive, onError]);
// This effect puts the `movieClip` on the `stage`, when both are ready.
React.useEffect(() => {
@@ -305,7 +307,7 @@ function loadScriptTag(src) {
const MOVIE_LIBRARY_CACHE = new LRU(10);
-export function loadMovieLibrary(librarySrc) {
+export function loadMovieLibrary(librarySrc, { preferArchive = false } = {}) {
const cancelableResourcePromises = [];
const cancelAllResources = () =>
cancelableResourcePromises.forEach((p) => p.cancel());
@@ -323,7 +325,9 @@ export function loadMovieLibrary(librarySrc) {
}
// Then, load the script tag. (Make sure we set it up to be cancelable!)
- const scriptPromise = loadScriptTag(safeImageUrl(librarySrc));
+ const scriptPromise = loadScriptTag(
+ safeImageUrl(librarySrc, { preferArchive })
+ );
cancelableResourcePromises.push(scriptPromise);
await scriptPromise;
@@ -372,6 +376,7 @@ export function loadMovieLibrary(librarySrc) {
id,
loadImage(librarySrcDir + "/" + src, {
crossOrigin: "anonymous",
+ preferArchive,
}),
])
);
diff --git a/src/app/components/OutfitPreview.js b/src/app/components/OutfitPreview.js
index 940c398..7e3e263 100644
--- a/src/app/components/OutfitPreview.js
+++ b/src/app/components/OutfitPreview.js
@@ -20,6 +20,7 @@ import OutfitMovieLayer, {
import HangerSpinner from "./HangerSpinner";
import { loadImage, safeImageUrl, useLocalStorage } from "../util";
import useOutfitAppearance from "./useOutfitAppearance";
+import usePreferArchive from "./usePreferArchive";
/**
* OutfitPreview is for rendering a full outfit! It accepts outfit data,
@@ -169,6 +170,7 @@ export function OutfitLayers({
...props
}) {
const [hiResMode] = useLocalStorage("DTIHiResMode", false);
+ const [preferArchive] = usePreferArchive();
const containerRef = React.useRef(null);
const [canvasSize, setCanvasSize] = React.useState(0);
@@ -281,7 +283,8 @@ export function OutfitLayers({
({
library,
@@ -465,7 +471,7 @@ export function usePreloadLayers(layers) {
return () => {
canceled = true;
};
- }, [layers, hiResMode]);
+ }, [layers, hiResMode, preferArchive]);
return { loading, error, loadedLayers, layersHaveAnimations };
}
diff --git a/src/app/components/SquareItemCard.js b/src/app/components/SquareItemCard.js
index 09df265..1ed643a 100644
--- a/src/app/components/SquareItemCard.js
+++ b/src/app/components/SquareItemCard.js
@@ -12,6 +12,7 @@ import Link from "next/link";
import { safeImageUrl, useCommonStyles } from "../util";
import { CheckIcon, CloseIcon, StarIcon } from "@chakra-ui/icons";
+import usePreferArchive from "./usePreferArchive";
function SquareItemCard({
item,
@@ -183,6 +184,7 @@ function SquareItemCardLayout({
}
function ItemThumbnail({ item, tradeMatchingMode }) {
+ const [preferArchive] = usePreferArchive();
const kindColorScheme = item.isNc ? "purple" : item.isPb ? "orange" : "gray";
const thumbnailShadowColor = useColorModeValue(
@@ -229,7 +231,7 @@ function ItemThumbnail({ item, tradeMatchingMode }) {
>
{/* eslint-disable-next-line @next/next/no-img-element */}
})