AI-Generated Code, an experiment by Tom Cranstoun
A simple prompt and its results are all done in Claude with help from context files. The details are listed below.
There is an invite to Adobe’s AEM Support Discord channel in the article to see more developments
Cube
The image below is a translucent, 3d Cube; click, drag and rotate it with the mouse;
Double-click on a face to go to the url linked.
An experiment in AI, created with the one-shot prompt-
“Create and implement the code, styling and readme for a Franklin 6-sided 3D cube named 3dcube, the readme should include the guidance you respond with as text. Each face should contain an image as a href link. The images are placed in the block’s first cell of each table row; the next cell is the link, as an href - use the href as the target. The cube should be rotatable in all directions. The mouse should be rotatable without clicking when it is over the image. Use the double-click action to move to the href page. On page load, place image 1 in the correct position”
Introduction
I have written many articles about Document Authoring with Adobe Edge Delivery Services, including how to use AI to help you on your journey.
I volunteered to talk on Adobe’s Discord Channel https://www.aem.live/community
So I bit the bullet and did a thing!
A simple prompt and its results are all done in Claude with help from context files. The details are listed below. Since then, I have improved the techniques added Cursor.AI. Please attend the Discord meeting to see much more.
The files
As always, here are the files, untouched by human hand
README.md
# 3D Cube Block
The 3D Cube block creates an interactive, rotatable 3D cube with images on each face that link to specified URLs.
## Features
- 6-sided 3D cube with images on each face
- Rotatable in all directions using mouse movement
- Double-click to navigate to the linked page
- Responsive design
## Usage
To use the 3D Cube block in your Franklin project, create a block with the following structure:
| Image | Link |
|-------|------|
| ![Front face image](path/to/front-image.jpg) | <https://example.com/front> |
| ![Back face image](path/to/back-image.jpg) | <https://example.com/back> |
| ![Right face image](path/to/right-image.jpg) | <https://example.com/right> |
| ![Left face image](path/to/left-image.jpg) | <https://example.com/left> |
| ![Top face image](path/to/top-image.jpg) | <https://example.com/top> |
| ![Bottom face image](path/to/bottom-image.jpg) | <https://example.com/bottom> |
The block will automatically create a 3D cube with the provided images and links.
## Interaction
- Hover over the cube to rotate it freely without clicking
- Click and drag to rotate the cube manually
- Double-click on a face to navigate to the associated link
## Customization
You can customize the appearance of the cube by modifying the `3dcube.css` file. Adjust the cube size, face opacity, and other properties as needed.
## Accessibility and SEO
The 3D Cube block is designed with accessibility and SEO in mind:
- Images have appropriate alt text (inherited from the original image tags)
- Links are standard `<a>` tags, making them crawlable by search engines
- The cube can be rotated using mouse or touch interactions
## Performance
The block uses CSS 3D transforms for smooth performance and minimal JavaScript overhead. Images are loaded as background images to prevent unnecessary DOM elements.
## Browser Support
This block uses modern CSS and JavaScript features. It should work in all modern browsers that support CSS 3D transforms.
3dcube.css
/* css */
.cube {
width: 200px;
height: 200px;
position: relative;
transform-style: preserve-3d;
transition: transform 0.5s;
cursor: grab;
}
.cube:active {
cursor: grabbing;
}
.cube__face {
position: absolute;
width: 200px;
height: 200px;
background-size: cover;
background-position: center;
opacity: 0.8;
transition: opacity 0.3s;
}
.cube__face:hover {
opacity: 1;
}
.cube__face--front { transform: rotateY( 0deg) translateZ(100px); }
.cube__face--right { transform: rotateY( 90deg) translateZ(100px); }
.cube__face--back { transform: rotateY(180deg) translateZ(100px); }
.cube__face--left { transform: rotateY(-90deg) translateZ(100px); }
.cube__face--top { transform: rotateX( 90deg) translateZ(100px); }
.cube__face--bottom { transform: rotateX(-90deg) translateZ(100px); }
@media (max-width: 768px) {
.cube {
width: 150px;
height: 150px;
}
.cube__face {
width: 150px;
height: 150px;
}
.cube__face--front { transform: rotateY( 0deg) translateZ(75px); }
.cube__face--right { transform: rotateY( 90deg) translateZ(75px); }
.cube__face--back { transform: rotateY(180deg) translateZ(75px); }
.cube__face--left { transform: rotateY(-90deg) translateZ(75px); }
.cube__face--top { transform: rotateX( 90deg) translateZ(75px); }
.cube__face--bottom { transform: rotateX(-90deg) translateZ(75px); }
}
3dcube.js
//js
export default async function decorate(block) {
const cube = document.createElement('div');
cube.className = 'cube';
const faces = ['front', 'back', 'right', 'left', 'top', 'bottom'];
const rows = [...block.children];
faces.forEach((face, index) => {
if (rows[index]) {
const [imageCell, linkCell] = rows[index].children;
const img = imageCell.querySelector('img');
const link = linkCell.querySelector('a');
if (img && link) {
const faceSide = document.createElement('div');
faceSide.className = `cube__face cube__face--${face}`;
faceSide.style.backgroundImage = `url(${img.src})`;
faceSide.dataset.href = link.href;
cube.appendChild(faceSide);
}
}
});
block.textContent = '';
block.appendChild(cube);
let isDragging = false;
let previousMousePosition = { x: 0, y: 0 };
let rotationX = 0;
let rotationY = 0;
const handleMouseMove = (e) => {
if (!isDragging) return;
const deltaMove = {
x: e.clientX - previousMousePosition.x,
y: e.clientY - previousMousePosition.y,
};
rotationY += deltaMove.x * 0.5;
rotationX -= deltaMove.y * 0.5;
cube.style.transform = `rotateX(${rotationX}deg) rotateY(${rotationY}deg)`;
previousMousePosition = { x: e.clientX, y: e.clientY };
};
cube.addEventListener('mousedown', (e) => {
isDragging = true;
previousMousePosition = { x: e.clientX, y: e.clientY };
});
document.addEventListener('mouseup', () => {
isDragging = false;
});
document.addEventListener('mousemove', handleMouseMove);
cube.addEventListener('dblclick', (e) => {
const face = e.target.closest('.cube__face');
if (face && face.dataset.href) {
window.location.href = face.dataset.href;
}
});
// Position the first image correctly on page load
rotationY = -90;
cube.style.transform = `rotateX(0deg) rotateY(${rotationY}deg)`;
}
The Table in Google Docs (first part only)
OK, it is still very techy, but what a step forward. I have improved this; see adobe’s AEM Support Discord channel https://www.aem.live/community
READ THIS, THANKS
Digital Domain Technologies Ltd is a consultancy that helps you do the work.
Read the advert below, and get in touch. tom@digitaldomaintechnologies.com
Related Articles