diff --git a/plugins/carhop-blocks/src/image-stack/block.json b/plugins/carhop-blocks/src/image-stack/block.json
new file mode 100755
index 0000000..b5c19c2
--- /dev/null
+++ b/plugins/carhop-blocks/src/image-stack/block.json
@@ -0,0 +1,65 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "carhop-blocks/image-stack",
+ "version": "0.1.0",
+ "title": "Image Stack (Focal Point)",
+ "category": "carhop-blocks",
+ "icon": "images-alt2",
+ "description": "Layer multiple images with individual focal point positioning.",
+ "example": {
+ "attributes": {
+ "images": [
+ {
+ "id": 1,
+ "url": "https://images.unsplash.com/photo-1506905925346-21bda4d32df4",
+ "alt": "Mountain landscape",
+ "focalPoint": {
+ "x": 0.5,
+ "y": 0.3
+ },
+ "scale": 0.8
+ },
+ {
+ "id": 2,
+ "url": "https://images.unsplash.com/photo-1511884642898-4c92249e20b6",
+ "alt": "Forest scene",
+ "focalPoint": {
+ "x": 0.7,
+ "y": 0.6
+ },
+ "scale": 0.6
+ }
+ ],
+ "height": 400
+ }
+ },
+ "attributes": {
+ "images": {
+ "type": "array",
+ "default": [],
+ "items": {
+ "type": "object"
+ }
+ },
+ "height": {
+ "type": "number",
+ "default": 400
+ }
+ },
+ "supports": {
+ "html": false,
+ "align": [
+ "wide",
+ "full"
+ ],
+ "spacing": {
+ "margin": true,
+ "padding": true
+ }
+ },
+ "textdomain": "image-stack",
+ "editorScript": "file:./index.js",
+ "editorStyle": "file:./index.css",
+ "style": "file:./style-index.css"
+}
\ No newline at end of file
diff --git a/plugins/carhop-blocks/src/image-stack/edit.js b/plugins/carhop-blocks/src/image-stack/edit.js
new file mode 100755
index 0000000..9418a95
--- /dev/null
+++ b/plugins/carhop-blocks/src/image-stack/edit.js
@@ -0,0 +1,243 @@
+import { __ } from "@wordpress/i18n";
+import {
+ useBlockProps,
+ InspectorControls,
+ MediaUpload,
+ MediaUploadCheck,
+} from "@wordpress/block-editor";
+import {
+ PanelBody,
+ Button,
+ FocalPointPicker,
+ RangeControl,
+ ToolbarGroup,
+ ToolbarButton,
+} from "@wordpress/components";
+import { BlockControls } from "@wordpress/block-editor";
+import { useState } from "@wordpress/element";
+
+import "./editor.scss";
+
+export default function Edit({ attributes, setAttributes }) {
+ const { images, height } = attributes;
+ const [selectedImageIndex, setSelectedImageIndex] = useState(null);
+
+ const blockProps = useBlockProps();
+
+ const onSelectImages = (media) => {
+ const newImages = media.map((img) => ({
+ id: img.id,
+ url: img.url,
+ alt: img.alt || "",
+ focalPoint: { x: 0.5, y: 0.5 },
+ scale: 0.8,
+ rotation: 0,
+ }));
+ setAttributes({ images: [...images, ...newImages] });
+ };
+
+ const updateImageFocalPoint = (index, focalPoint) => {
+ const newImages = [...images];
+ newImages[index] = { ...newImages[index], focalPoint };
+ setAttributes({ images: newImages });
+ };
+
+ const updateImageScale = (index, scale) => {
+ const newImages = [...images];
+ newImages[index] = { ...newImages[index], scale };
+ setAttributes({ images: newImages });
+ };
+
+ const updateImageRotation = (index, rotation) => {
+ const newImages = [...images];
+ newImages[index] = { ...newImages[index], rotation };
+ setAttributes({ images: newImages });
+ };
+
+ const removeImage = (index) => {
+ const newImages = images.filter((_, i) => i !== index);
+ setAttributes({ images: newImages });
+ if (selectedImageIndex === index) {
+ setSelectedImageIndex(null);
+ }
+ };
+
+ const moveImage = (index, direction) => {
+ const newImages = [...images];
+ const newIndex = index + direction;
+ if (newIndex >= 0 && newIndex < images.length) {
+ [newImages[index], newImages[newIndex]] = [
+ newImages[newIndex],
+ newImages[index],
+ ];
+ setAttributes({ images: newImages });
+ setSelectedImageIndex(newIndex);
+ }
+ };
+
+ const getImageStyle = (image) => {
+ const focalPoint = image.focalPoint || { x: 0.5, y: 0.5 };
+ const scale = image.scale || 0.8;
+ const rotation = image.rotation || 0;
+ return {
+ left: `${focalPoint.x * 100}%`,
+ top: `${focalPoint.y * 100}%`,
+ transform: ` rotate(${rotation}deg) scale(${scale})`,
+ };
+ };
+
+ return (
+ <>
+
+
+
+ img.id)}
+ render={({ open }) => (
+
+ {__("Add Images", "image-stack")}
+
+ )}
+ />
+
+
+
+
+
+
+ setAttributes({ height: value })}
+ min={200}
+ max={800}
+ step={10}
+ />
+
+
+ {images.length > 0 && (
+
+ {images.map((image, index) => (
+
+ setSelectedImageIndex(
+ selectedImageIndex === index ? null : index
+ )
+ }
+ >
+
+

+
+
+
+ updateImageFocalPoint(index, focalPoint)
+ }
+ />
+
+ updateImageScale(index, scale)}
+ min={0.1}
+ max={3}
+ step={0.05}
+ />
+
+ updateImageRotation(index, rotation)}
+ min={-180}
+ max={180}
+ step={1}
+ />
+
+
+
+
+
+
+
+ ))}
+
+ )}
+
+
+
+
+ {images.length === 0 && (
+
+
+ (
+
+ )}
+ />
+
+
+ )}
+
+ {images.map((image, index) => (
+
setSelectedImageIndex(index)}
+ role="button"
+ tabIndex={0}
+ onKeyDown={(e) => {
+ if (e.key === "Enter" || e.key === " ") {
+ setSelectedImageIndex(index);
+ }
+ }}
+ style={getImageStyle(image)}
+ >
+

+
+ ))}
+
+
+ >
+ );
+}
diff --git a/plugins/carhop-blocks/src/image-stack/editor.scss b/plugins/carhop-blocks/src/image-stack/editor.scss
new file mode 100755
index 0000000..544b762
--- /dev/null
+++ b/plugins/carhop-blocks/src/image-stack/editor.scss
@@ -0,0 +1,56 @@
+/**
+ * The following styles get applied inside the editor only.
+ */
+
+.wp-block-carhop-blocks-image-stack {
+ overflow: visible;
+ .image-stack-placeholder {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(240, 240, 240, 0.5);
+ background-color: red;
+ border: 2px dashed #ccc;
+ }
+
+ .image-stack-item {
+ cursor: pointer;
+ transition: opacity 0.2s ease;
+
+ &:hover {
+ opacity: 0.9;
+ }
+
+ &.is-selected {
+ outline: 3px solid #007cba;
+ outline-offset: -3px;
+ z-index: 10;
+ }
+ }
+}
+
+.image-stack-image-preview {
+ margin-bottom: 16px;
+
+ img {
+ width: 100%;
+ height: auto;
+ display: block;
+ border-radius: 4px;
+ }
+}
+
+.image-stack-image-controls {
+ display: flex;
+ gap: 8px;
+ margin-top: 16px;
+ flex-wrap: wrap;
+
+ .components-button {
+ flex: 1;
+ min-width: 80px;
+ justify-content: center;
+ }
+}
diff --git a/plugins/carhop-blocks/src/image-stack/index.js b/plugins/carhop-blocks/src/image-stack/index.js
new file mode 100755
index 0000000..d537a9d
--- /dev/null
+++ b/plugins/carhop-blocks/src/image-stack/index.js
@@ -0,0 +1,11 @@
+import { registerBlockType } from "@wordpress/blocks";
+import "./style.scss";
+
+import Edit from "./edit";
+import save from "./save";
+import metadata from "./block.json";
+
+registerBlockType(metadata.name, {
+ edit: Edit,
+ save,
+});
diff --git a/plugins/carhop-blocks/src/image-stack/save.js b/plugins/carhop-blocks/src/image-stack/save.js
new file mode 100755
index 0000000..7af7734
--- /dev/null
+++ b/plugins/carhop-blocks/src/image-stack/save.js
@@ -0,0 +1,33 @@
+import { useBlockProps } from "@wordpress/block-editor";
+
+export default function save({ attributes }) {
+ const { images, height } = attributes;
+ const blockProps = useBlockProps.save();
+
+ const getImageStyle = (image) => {
+ const focalPoint = image.focalPoint || { x: 0.5, y: 0.5 };
+ const scale = image.scale || 0.8;
+ const rotation = image.rotation || 0;
+ return {
+ left: `${focalPoint.x * 100}%`,
+ top: `${focalPoint.y * 100}%`,
+ transform: `rotate(${rotation}deg) scale(${scale})`,
+ };
+ };
+
+ return (
+
+
+ {images.map((image) => (
+
+

+
+ ))}
+
+
+ );
+}
diff --git a/plugins/carhop-blocks/src/image-stack/style.scss b/plugins/carhop-blocks/src/image-stack/style.scss
new file mode 100755
index 0000000..5b0195e
--- /dev/null
+++ b/plugins/carhop-blocks/src/image-stack/style.scss
@@ -0,0 +1,23 @@
+/**
+ * The following styles get applied both on the front of your site
+ * and in the editor.
+ */
+
+.wp-block-carhop-blocks-image-stack {
+ .image-stack-container {
+ position: relative;
+ width: 100%;
+ overflow: visible;
+ }
+
+ .image-stack-item {
+ position: absolute;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ display: block;
+ }
+ }
+}
diff --git a/plugins/carhop-blocks/src/image-stack/view.js b/plugins/carhop-blocks/src/image-stack/view.js
new file mode 100755
index 0000000..a1f041b
--- /dev/null
+++ b/plugins/carhop-blocks/src/image-stack/view.js
@@ -0,0 +1,5 @@
+/**
+ * Frontend JavaScript for the Image Stack block.
+ * Currently no interactive features required, but this file
+ * is available for future enhancements.
+ */