diff --git a/src/components/map/TiledLayer.test.tsx b/src/components/map/TiledLayer.test.tsx
new file mode 100644
index 0000000..f4691cc
--- /dev/null
+++ b/src/components/map/TiledLayer.test.tsx
@@ -0,0 +1,165 @@
+import { renderHook, act, render, screen } from '@testing-library/react';
+import { useAtom } from 'jotai';
+import LayerStack from './LayerStack';
+import { coordinateSystemAtom, relativeCoordinateSystemAtom } from './Map';
+import TiledLayer from './TiledLayer';
+
+describe('The TiledLayer component', () => {
+ beforeEach(() => {
+ globalThis.cacheForTileSet = new Map();
+ });
+
+ test('generates an empty layer if inactive', () => {
+ // const { result } = renderHook(() => useAtom(tiledLayersAtom));
+ render(
+
+ );
+ const svg = screen.getByTestId('tiled-layer');
+ expect(svg).toMatchInlineSnapshot(`
+
+`);
+ });
+ test('generates a populated layer if active', () => {
+ // const { result } = renderHook(() => useAtom(tiledLayersAtom));
+ render(
+
+ );
+ const svg = screen.getByTestId('tiled-layer');
+ expect(svg).toMatchInlineSnapshot(`
+
+`);
+ });
+});
diff --git a/src/components/map/TiledLayer.tsx b/src/components/map/TiledLayer.tsx
new file mode 100644
index 0000000..7f1d6c2
--- /dev/null
+++ b/src/components/map/TiledLayer.tsx
@@ -0,0 +1,85 @@
+import { useAtom } from 'jotai';
+import react from 'react';
+import TileSet from './TileSet';
+import { Point, TileKeyObject } from './types';
+import { coordinateSystemAtom } from './Map';
+
+export interface TiledLayerProperties {
+ /**
+ * A key identifying the top left tile
+ */
+ keyObject: TileKeyObject;
+ /**
+ * A flag to indicate if the layer is active and should add tiles which are in its viewport or if it is "only" a backup.
+ */
+ shift: Point;
+ /**
+ * The zoom to apply. If equal to 1, the layer is considered active and should add tiles which are in its viewport
+ */
+ zoom: number;
+}
+
+/**
+ *
+ * @param props
+ * @returns A layer of tiles.
+ * This component wraps a `` in an SVG `` element taking care of the scale and translation.
+ *
+ */
+export const TiledLayer: react.FC = (
+ props: TiledLayerProperties
+) => {
+ const [coordinateSystem] = useAtom(coordinateSystemAtom);
+ const viewPort =
+ props.zoom === 1
+ ? {
+ topLeft: {
+ x:
+ props.keyObject.x +
+ Math.floor(
+ -coordinateSystem.shift.x / coordinateSystem.zoom / 256
+ ),
+ y:
+ props.keyObject.y +
+ Math.floor(
+ -coordinateSystem.shift.y / coordinateSystem.zoom / 256
+ ),
+ },
+ bottomRight: {
+ x:
+ props.keyObject.x +
+ Math.ceil(
+ (-coordinateSystem.shift.x + window.innerWidth) /
+ coordinateSystem.zoom /
+ 256
+ ) -
+ 1,
+ y:
+ props.keyObject.y +
+ Math.ceil(
+ (-coordinateSystem.shift.y + window.innerHeight) /
+ coordinateSystem.zoom /
+ 256
+ ) -
+ 1,
+ },
+ }
+ : undefined;
+ return (
+
+
+
+ );
+};
+
+export default TiledLayer;