diff --git a/packages/snips/package.json b/packages/snips/package.json
index 9fdebca34ef2a8753c07a53454c3121b07515efa..d2012882f31c1fcaf627ea06854230e3bafef028 100644
--- a/packages/snips/package.json
+++ b/packages/snips/package.json
@@ -29,6 +29,7 @@
         "@types/sprintf-js": "^1.1.4",
         "tree-sitter-cli": "^0.25.1",
         "tree-sitter-python": "^0.23.6",
+        "skia-canvas": "catalog:",
         "tsup": "catalog:",
         "typescript": "catalog:",
         "vitest": "catalog:"
@@ -39,7 +40,8 @@
         "build": "tsup",
         "watch": "tsc -w",
         "test": "vitest",
-        "generate-grammars": "tree-sitter build --wasm node_modules/tree-sitter-python -o ../../assets/grammars/tree-sitter-python.wasm"
+        "generate-grammars": "tree-sitter build --wasm node_modules/tree-sitter-python -o ../../assets/grammars/tree-sitter-python.wasm",
+        "json_to_snip": "tsx ./src/json_to_snip.ts"
     },
     "type": "module"
 }
diff --git a/packages/snips/src/general/text.ts b/packages/snips/src/general/text.ts
index f2749ea2cd5db93c161fb2d0b407e90c68b8652b..b3dbb47b98570edad6b310c892d71306003f2b41 100644
--- a/packages/snips/src/general/text.ts
+++ b/packages/snips/src/general/text.ts
@@ -265,15 +265,15 @@ export class TextSnip extends BaseSnip {
             lineWrap: validation.view?.wrap,
             baseline: validation.view?.baseline,
             //Base
-            id: data.id,
-            page_id: data.page_id,
-            book_id: data.book_id,
-            last_updated: data.last_updated,
-            created: data.created,
-            x: data.view?.x,
-            y: data.view?.y,
-            rot: data.view?.rot,
-            mirror: data.view?.mirror,
+            id: validation.id,
+            page_id: validation.page_id,
+            book_id: validation.book_id,
+            last_updated: validation.last_updated,
+            created: validation.created,
+            x: validation.view?.x,
+            y: validation.view?.y,
+            rot: validation.view?.rot,
+            mirror: validation.view?.mirror,
         });
     }
 
diff --git a/packages/snips/src/json_to_snip.ts b/packages/snips/src/json_to_snip.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ad3030eb82c5f56c4efc4c4aeb6ea8e55deab46f
--- /dev/null
+++ b/packages/snips/src/json_to_snip.ts
@@ -0,0 +1,52 @@
+/** Debugging script to render a snippet
+ *
+ * Can be use to develop a new snippet type and test it easily.
+ */
+
+import fs from "fs";
+import { Canvas } from "skia-canvas";
+
+import { get_snip_from_data } from "./get_snip_from_data";
+
+const file_name = process.argv[2];
+let output_file = process.argv[3];
+
+if (!file_name) {
+    console.error("Usage: tsx render_json.ts <file_name> [output_file]");
+    process.exit(1);
+}
+
+if (output_file && !output_file.endsWith(".png")) {
+    console.error("Output file must be a PNG file");
+    process.exit(1);
+}
+
+if (!fs.existsSync(file_name)) {
+    console.error("File does not exist");
+    process.exit(1);
+}
+
+if (!output_file) {
+    console.log("No output file specified, rendering to output.png");
+    output_file = "./output.png";
+}
+
+// Read file as JSON
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+let data: any;
+try {
+    const f = fs.readFileSync(file_name, "utf8");
+    data = JSON.parse(f);
+} catch (e) {
+    console.error(`Error reading file: ${e}`);
+    process.exit(1);
+}
+
+const snip = get_snip_from_data(data);
+
+const canvas = new Canvas(2100, 1400);
+const ctx = canvas.getContext("2d");
+snip.render(ctx as unknown as OffscreenCanvasRenderingContext2D);
+
+// Save to file
+canvas.saveAsSync(output_file);
diff --git a/packages/snips/src/uprp/__mapping.ts b/packages/snips/src/uprp/__mapping.ts
index 2ba7f7d4597d10ef09754e41250a464c6e3be6f3..645fa2027b595a1d2e2adc396305ac945ffe8b4b 100644
--- a/packages/snips/src/uprp/__mapping.ts
+++ b/packages/snips/src/uprp/__mapping.ts
@@ -5,6 +5,7 @@ import { LogfileSnip } from "./spec/logfile";
 import { MacroSpecSnip } from "./spec/macrospec";
 import { MotorsSnip } from "./spec/motors";
 import { TimestampSnip } from "./spec/timestamp";
+import { StampySnip } from "./stampy";
 
 const TYPE_TO_SNIP: Map<string, typeof BaseSnip> = new Map();
 
@@ -25,4 +26,7 @@ TYPE_TO_SNIP.set("uprp/spec/matlab", ImageSnip);
 // SPOC mapping
 // TODO:@Markus
 
+// Stampy
+TYPE_TO_SNIP.set("uprp/stampy", StampySnip);
+
 export default TYPE_TO_SNIP;
diff --git a/packages/snips/src/uprp/stampy.ts b/packages/snips/src/uprp/stampy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f5bd5a72b79a3e16520312f7764276c0cd43928e
--- /dev/null
+++ b/packages/snips/src/uprp/stampy.ts
@@ -0,0 +1,199 @@
+import { type } from "arktype";
+
+import { DataValidationError } from "@/errors";
+import {
+    BaseSnip,
+    BaseSnipArgs,
+    BaseViewSchema,
+    RenderContext,
+    SnipData,
+    SnipDataSchema,
+} from "@/general/base";
+
+/* -------------------------------------------------------------------------- */
+/*                              Schema for insert                             */
+/* -------------------------------------------------------------------------- */
+// The dataschema is a one to one mapping from the stampy json
+// TODO: Might need some adjustments depending on what we actually need on the snip side
+// I would suggest to remove all the optional fields and only keep the required ones
+
+const StampySchema = type({
+    meta: {
+        version: "number",
+        instrument: "string",
+        setup: "string",
+        experiment: "string",
+        date: "string",
+    },
+    sample: {
+        name: "string",
+        id: "number",
+        comment: "string",
+    },
+    measurement: {
+        volume: {
+            diameter: "number",
+            height: "number",
+            fovw: "number",
+            fovh: "number",
+            unit: "'mm' | 'cm'",
+        },
+        stack: {
+            motor: "string",
+            factorh: "number",
+            values: "number[]",
+        },
+        detector: {
+            name: "string",
+            pixelSize: "number",
+            pixels: ["number", "number"],
+        },
+        grid: {
+            motors: "('cx'|'cy')[]",
+            method: "'hexagonal'",
+            factorw: "number",
+            prefill: "number",
+            values: "number[][]",
+        },
+        timing: {
+            illumination: "number",
+            interval: "number",
+            unit: "'second' | 'minute' | 'hour'",
+            mode: "string",
+            topupSync: "'no' | 'yes'",
+            topupParameter: "number[]",
+            trgLine: "number",
+            trgDelay: "number",
+        },
+        tomo: {
+            motor: "string",
+            frames: "number",
+            commands: "string[]",
+            angles: {
+                range: "number",
+                safety: "number",
+                unit: "string",
+            },
+            velocity: {
+                tomo: "number",
+                moving: "number",
+            },
+        },
+        empty: {
+            frames: "number",
+            commands: "string[]",
+            scheme: "string",
+            pattern: "string",
+        },
+        dark: {
+            frames: "number",
+            commands: "string[]",
+        },
+        range: "string",
+    },
+    motors: {
+        tomo: {
+            stx: "number",
+            cx: "number",
+            sty: "number",
+            cy: "number",
+            stz: "number",
+            cz: "number",
+            stzrot: "number",
+        },
+        empty: {
+            stx: "number",
+            cx: "number",
+            sty: "number",
+            cy: "number",
+            stz: "number",
+            cz: "number",
+            stzrot: "number",
+        },
+        final: {
+            stx: "number",
+            cx: "number",
+            sty: "number",
+            cy: "number",
+            stz: "number",
+            cz: "number",
+            stzrot: "number",
+        },
+    },
+});
+
+export const StampyDataSchema = type({
+    "version?": type("1").describe(
+        "The version of the stampy snippet, empty for latest.",
+    ),
+    stampy: StampySchema.describe("The data returned from stampy."),
+});
+
+export const StampyViewSchema = type({}, "&", BaseViewSchema).describe(
+    BaseViewSchema.description,
+);
+
+export const StampySnipSchema = type(SnipDataSchema, "&", {
+    data: StampyDataSchema,
+    "view?": StampyViewSchema,
+}).describe("Represents a stampy snippet.");
+
+export type StampyData = typeof StampyDataSchema.infer;
+export type StampyView = typeof StampyViewSchema.infer;
+
+export type StampySnipArgs = BaseSnipArgs & StampyData;
+
+/* -------------------------------------------------------------------------- */
+/*                          StampySnip implementation                         */
+/* -------------------------------------------------------------------------- */
+
+export class StampySnip extends BaseSnip {
+    public type = "stampy";
+
+    stampy: StampyData["stampy"];
+
+    constructor({ version, stampy, ...baseArgs }: StampySnipArgs) {
+        super({ ...baseArgs });
+
+        this.stampy = stampy;
+    }
+
+    static readonly _schema = StampySnipSchema;
+    static from_data(data: SnipData<StampyData, StampyView>): StampySnip {
+        // Validate
+        const validation = this._schema(data);
+        if (validation instanceof type.errors) {
+            throw DataValidationError.from_ark(validation);
+        }
+
+        // We can check the version here if necessary
+        // in the future
+
+        return new StampySnip({
+            stampy: validation.data.stampy,
+
+            // Base
+            id: validation.id,
+            page_id: validation.page_id,
+            book_id: validation.book_id,
+            last_updated: validation.last_updated,
+            created: validation.created,
+            x: validation.view?.x,
+            y: validation.view?.y,
+            rot: validation.view?.rot,
+            mirror: validation.view?.mirror,
+        });
+    }
+
+    // TODO: Implement this method
+    get width(): number {
+        return 0;
+    }
+    get height(): number {
+        return 0;
+    }
+
+    public render(ctx: RenderContext): void {
+        throw new Error("Render method not implemented.");
+    }
+}
diff --git a/packages/snips/stampy_example_snip.json b/packages/snips/stampy_example_snip.json
new file mode 100644
index 0000000000000000000000000000000000000000..d6b21bd012c3e795eeffba7cd604d61ceccb96bc
--- /dev/null
+++ b/packages/snips/stampy_example_snip.json
@@ -0,0 +1,100 @@
+{
+    "type": "uprp/stampy",
+    "book_id": -1,
+    "data": {
+        "stampy": {
+            "meta": {
+                "version": 1,
+                "instrument": "GINIX",
+                "setup": "PB tomo",
+                "experiment": "run123",
+                "date": "2024-9-27"
+            },
+            "sample": {
+                "name": "sample01a",
+                "id": 0,
+                "comment": "NR_PREV\\nImaging of top part"
+            },
+            "measurement": {
+                "volume": {
+                    "diameter": 1,
+                    "height": 1,
+                    "fovw": 1.4,
+                    "fovh": 1.2,
+                    "unit": "mm"
+                },
+                "stack": { "motor": "stz", "factorh": 1.1, "values": [0] },
+                "detector": {
+                    "name": "PCO.edge",
+                    "pixelSize": 0.65e-6,
+                    "pixels": [2560, 2160]
+                },
+                "grid": {
+                    "motors": ["cx", "cy"],
+                    "method": "hexagonal",
+                    "factorw": 1.1,
+                    "prefill": 1,
+                    "values": [[0, 0]]
+                },
+                "timing": {
+                    "illumination": 0.035,
+                    "interval": 0.015,
+                    "unit": "second",
+                    "mode": "continuous-1",
+                    "topupSync": "no",
+                    "topupParameter": [100.9, 100.8],
+                    "trgLine": 2,
+                    "trgDelay": 2000
+                },
+                "tomo": {
+                    "motor": "stzrot",
+                    "frames": 3000,
+                    "commands": ["oslow; sleep(1);", "cslow;"],
+                    "angles": {
+                        "range": 360.014,
+                        "safety": 20,
+                        "unit": "degree"
+                    },
+                    "velocity": { "tomo": 11972, "moving": 240000 }
+                },
+                "empty": {
+                    "frames": 500,
+                    "commands": ["", ""],
+                    "scheme": "pre-volume",
+                    "pattern": "eted"
+                },
+                "dark": { "frames": 100, "commands": ["cslow; sleep(1);", ""] },
+                "range": "all"
+            },
+            "motors": {
+                "tomo": {
+                    "stx": 180,
+                    "cx": 2.50001,
+                    "sty": -3.94607,
+                    "cy": 1.60297,
+                    "stz": -1,
+                    "cz": 2.07352,
+                    "stzrot": 0.000194
+                },
+                "empty": {
+                    "stx": 180,
+                    "cx": 2.50001,
+                    "sty": -3.94607,
+                    "cy": -4,
+                    "stz": -1,
+                    "cz": 2.07352,
+                    "stzrot": 0.000194
+                },
+                "final": {
+                    "stx": 180,
+                    "cx": 2.50001,
+                    "sty": -3.94607,
+                    "cy": 1.60297,
+                    "stz": -1,
+                    "cz": 2.07352,
+                    "stzrot": 0.000194
+                }
+            }
+        }
+    }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c20323a78910cbb22f0c524345f02fbd84421bb2..89c15e72a4624d335c0e3d5fc2c8be312fb5ee2e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1013,6 +1013,9 @@ importers:
       '@types/sprintf-js':
         specifier: ^1.1.4
         version: 1.1.4
+      skia-canvas:
+        specifier: 'catalog:'
+        version: 2.0.2
       tree-sitter-cli:
         specifier: ^0.25.1
         version: 0.25.1