diff --git a/src/components/map/Tile.test.tsx b/src/components/map/Tile.test.tsx
new file mode 100644
index 0000000..1c09aa5
--- /dev/null
+++ b/src/components/map/Tile.test.tsx
@@ -0,0 +1,45 @@
+import { render, screen } from '@testing-library/react';
+import Tile from './Tile';
+
+describe('The Tile component ', () => {
+ test('Is initially empty', () => {
+ const { baseElement } = render(
+
+ );
+ screen.debug();
+ expect(baseElement).toMatchInlineSnapshot(`
+
+
+
+
+
+`);
+ });
+ test('Gets its image immediately with a fake URL', () => {
+ const { baseElement } = render(
+
+ );
+ screen.debug();
+ expect(baseElement).toMatchInlineSnapshot(`
+
+
+
+
+
+`);
+ });
+});
diff --git a/src/components/map/Tile.tsx b/src/components/map/Tile.tsx
new file mode 100644
index 0000000..757c0a1
--- /dev/null
+++ b/src/components/map/Tile.tsx
@@ -0,0 +1,53 @@
+import react, { useEffect, useRef } from 'react';
+
+export interface TileProperties {
+ // The image's source URL
+ href: string;
+ // Its size
+ size: number;
+ // A delay to add (for test/debug purposes)
+ delay?: number;
+}
+
+/**
+ *
+ * @param props
+ * @returns A tile
+ */
+export const Tile: react.FC = (props: TileProperties) => {
+ const g = useRef(null);
+
+ const timeout = (ms: number) => {
+ return new Promise((resolve) => setTimeout(resolve, ms));
+ };
+
+ useEffect(() => {
+ const loadImage = async () => {
+ console.log(`Pre loading: ${props.href}`);
+ const image = new Image(props.size, props.size);
+ image.loading = 'eager';
+ // @ts-ignore
+ image.setAttribute('href', props.href);
+ if (!image.complete) {
+ await image.decode();
+ }
+ if (props.delay !== undefined) {
+ await timeout(props.delay);
+ }
+ const svgImage = document.createElementNS(
+ 'http://www.w3.org/2000/svg',
+ 'image'
+ ) as unknown as SVGImageElement;
+ svgImage.setAttribute('width', props.size.toString());
+ svgImage.setAttribute('height', props.size.toString());
+ // @ts-ignore
+ svgImage.setAttribute('href', props.href);
+ g.current?.replaceChildren(svgImage);
+ };
+ loadImage();
+ }, [props.href, props.size]);
+
+ return ;
+};
+
+export default Tile;