diff --git a/source/code/_ui.js b/source/code/drag.js
similarity index 100%
rename from source/code/_ui.js
rename to source/code/drag.js
diff --git a/source/code/_intro.js b/source/code/intro.js
similarity index 100%
rename from source/code/_intro.js
rename to source/code/intro.js
diff --git a/source/code/windows.js b/source/code/windows.js
new file mode 100644
index 0000000..6c68eec
--- /dev/null
+++ b/source/code/windows.js
@@ -0,0 +1,282 @@
+class Draggable {
+ constructor(element) {
+ this.element = element;
+ this.offsetX = 0;
+ this.offsetY = 0;
+ this.isDragging = false;
+ this.barSize = '';
+
+ this.init();
+ }
+
+ init() {
+ this.element.addEventListener('mousedown', this.onMouseDown.bind(this));
+ document.addEventListener('mousemove', this.onMouseMove.bind(this));
+ document.addEventListener('mouseup', this.onMouseUp.bind(this));
+ this.setPosition('bottom');
+ }
+
+ onMouseDown(event) {
+ this.isDragging = true;
+ this.offsetX = event.clientX - this.element.getBoundingClientRect().left;
+ this.offsetY = event.clientY - this.element.getBoundingClientRect().top;
+
+ event.preventDefault();
+ }
+
+ onMouseMove(event) {
+ if (!this.isDragging) {
+ return;
+ }
+
+ let x = event.clientX - this.offsetX;
+ let y = event.clientY - this.offsetY;
+
+ // Update the position of the element
+ this.element.style.left = `${x}px`;
+ this.element.style.top = `${y}px`;
+ }
+
+ onMouseUp() {
+ if (!this.isDragging) {
+ return;
+ }
+ this.isDragging = false;
+
+ this.snapToEdges();
+ }
+
+ snapToEdges() {
+ const rect = this.element.getBoundingClientRect();
+ const windowWidth = window.innerWidth;
+ const windowHeight = window.innerHeight;
+
+ // Determine the closest edge
+ const distances = {
+ left: rect.left,
+ right: windowWidth - rect.right,
+ top: rect.top,
+ bottom: windowHeight - rect.bottom
+ };
+
+ const closestEdge = Object.keys(distances).reduce((a, b) => distances[a] < distances[b] ? a : b);
+
+ this.setPosition(closestEdge, this.barSize);
+ }
+
+ setPosition(side, barSize) {
+ switch (side) {
+ case 'left':
+ // this.element.style.top = `${rect.top}px`; // Optional: keep vertical position
+ this.element.style.top = '0px';
+ this.element.style.right = '';
+ this.element.style.bottom = '0px';
+ this.element.style.left = '0px';
+ this.element.style.width = barSize;
+ this.element.style.height = '';
+ break;
+ case 'right':
+ // this.element.style.left = `${windowWidth - rect.width}px`;
+ // this.element.style.top = `${rect.top}px`; // Optional: keep vertical position
+ this.element.style.top = '0px';
+ this.element.style.right = '0px';
+ this.element.style.bottom = '0px';
+ this.element.style.left = '';
+ this.element.style.width = barSize;
+ this.element.style.height = '';
+ break;
+ case 'top':
+ // this.element.style.top = '0px';
+ // this.element.style.left = `${rect.left}px`; // Optional: keep horizontal position
+ this.element.style.top = '0px';
+ this.element.style.right = '0px';
+ this.element.style.bottom = '';
+ this.element.style.left = '0px';
+ this.element.style.width = '';
+ this.element.style.height = barSize;
+ break;
+ case 'bottom':
+ // this.element.style.top = `${windowHeight - rect.height}px`;
+ // this.element.style.left = `${rect.left}px`; // Optional: keep horizontal position
+ this.element.style.top = '';
+ this.element.style.right = '0px';
+ this.element.style.bottom = '0px';
+ this.element.style.left = '0px';
+ this.element.style.width = '';
+ this.element.style.height = barSize;
+ break;
+ }
+ }
+}
+
+class DragAdv {
+ constructor(element, placeholder) {
+ this.element = element;
+ this.placeholder = placeholder;
+ this.offsetX = 0;
+ this.offsetY = 0;
+ this.isDragging = false;
+ this.barSize = '';
+
+ this.init();
+ }
+
+ init() {
+ this.element.addEventListener('mousedown', this.onMouseDown.bind(this));
+ document.addEventListener('mousemove', this.onMouseMove.bind(this));
+ document.addEventListener('mouseup', this.onMouseUp.bind(this));
+ this.setPosition('bottom');
+ }
+
+ onMouseDown(event) {
+ this.isDragging = true;
+ // this.offsetX = event.clientX - this.element.getBoundingClientRect().left;
+ // this.offsetY = event.clientY - this.element.getBoundingClientRect().top;
+ this.offsetX = 0;
+ this.offsetY = 0;
+ this.element.style.display = 'none';
+
+ this.showPlaceholder();
+ event.preventDefault();
+ }
+
+ onMouseMove(event) {
+ if (!this.isDragging) return;
+
+ let x = event.clientX - this.offsetX;
+ let y = event.clientY - this.offsetY;
+
+ // Update the position of the element
+ // this.element.style.left = `${x}px`;
+ // this.element.style.top = `${y}px`;
+ // this.element.style.display = 'none';
+
+ // Update placeholder position
+ this.placeholder.style.left = `${x}px`;
+ this.placeholder.style.top = `${y}px`;
+ // this.placeholder.style.display = 'block';
+ }
+
+ onMouseUp() {
+ if (!this.isDragging) return;
+ this.isDragging = false;
+
+ this.element.style.display = 'block';
+
+ this.snapToEdges();
+ this.hidePlaceholder();
+ }
+
+ showPlaceholder() {
+ this.placeholder.style.display = 'block';
+ }
+
+ hidePlaceholder() {
+ this.placeholder.style.display = 'none';
+ }
+
+ snapToEdges() {
+ const rect = this.placeholder.getBoundingClientRect();
+ const windowWidth = window.innerWidth;
+ const windowHeight = window.innerHeight;
+
+ const distances = {
+ left: rect.left,
+ right: windowWidth - rect.right,
+ top: rect.top,
+ bottom: windowHeight - rect.bottom
+ };
+
+ const closestEdge = Object.keys(distances).reduce((a, b) => distances[a] < distances[b] ? a : b);
+
+ console.log(rect);
+ console.log(closestEdge);
+ this.setPosition(closestEdge, this.barSize);
+ /*switch (closestEdge) {
+ case 'left':
+ this.element.style.left = '0px';
+ this.element.style.top = `${rect.top}px`;
+ break;
+ case 'right':
+ this.element.style.left = `${windowWidth - rect.width}px`;
+ this.element.style.top = `${rect.top}px`;
+ break;
+ case 'top':
+ this.element.style.top = '0px';
+ this.element.style.left = `${rect.left}px`;
+ break;
+ case 'bottom':
+ this.element.style.top = `${windowHeight - rect.height}px`;
+ this.element.style.left = `${rect.left}px`;
+ break;
+ }*/
+ }
+
+ setPosition(side, barSize) {
+ switch (side) {
+ case 'left':
+ // this.element.style.top = `${rect.top}px`; // Optional: keep vertical position
+ this.element.style.top = '0px';
+ this.element.style.right = '';
+ this.element.style.bottom = '0px';
+ this.element.style.left = '0px';
+ this.element.style.width = barSize;
+ this.element.style.height = '';
+ break;
+ case 'right':
+ // this.element.style.left = `${windowWidth - rect.width}px`;
+ // this.element.style.top = `${rect.top}px`; // Optional: keep vertical position
+ this.element.style.top = '0px';
+ this.element.style.right = '0px';
+ this.element.style.bottom = '0px';
+ this.element.style.left = '';
+ this.element.style.width = barSize;
+ this.element.style.height = '';
+ break;
+ case 'top':
+ // this.element.style.top = '0px';
+ // this.element.style.left = `${rect.left}px`; // Optional: keep horizontal position
+ this.element.style.top = '0px';
+ this.element.style.right = '0px';
+ this.element.style.bottom = '';
+ this.element.style.left = '0px';
+ this.element.style.width = '';
+ this.element.style.height = barSize;
+ break;
+ case 'bottom':
+ // this.element.style.top = `${windowHeight - rect.height}px`;
+ // this.element.style.left = `${rect.left}px`; // Optional: keep horizontal position
+ this.element.style.top = '';
+ this.element.style.right = '0px';
+ this.element.style.bottom = '0px';
+ this.element.style.left = '0px';
+ this.element.style.width = '';
+ this.element.style.height = barSize;
+ break;
+ }
+ }
+}
+
+class BestDrag {
+ #element;
+
+ constructor(element) {
+ this.#setElement(element);
+ }
+
+ #setElement(value) {
+ if (!value) {
+ throw new Error('No element found');
+ }
+ this.#element = value;
+ this.#element.style.background = "hotpink";
+ }
+
+ get element() {
+ return this.#element;
+ }
+
+ set element(value) {
+ this.#setElement(value);
+ }
+}
\ No newline at end of file
diff --git a/source/screens/demo/examples/intro.njk b/source/screens/demo/examples/intro.njk
index 1358739..548cc3f 100644
--- a/source/screens/demo/examples/intro.njk
+++ b/source/screens/demo/examples/intro.njk
@@ -49,7 +49,7 @@ tags:
{%- block script %}
{{ super() }}
-
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/source/style/modules/ui/_windows_module.scss b/source/style/modules/ui/_windows_module.scss
new file mode 100644
index 0000000..0f46b78
--- /dev/null
+++ b/source/style/modules/ui/_windows_module.scss
@@ -0,0 +1,36 @@
+@use "sass:map";
+
+@use "../../hippie-style/hippie";
+
+#task-bar {
+ @extend %flex-inline;
+ z-index: map.get(hippie.$z-indexes, "content-top");
+ align-items: stretch;
+ position: fixed;
+ //right: 0;
+ //bottom: 0;
+ //left: 0;
+ border: 1px solid transparent;
+ padding: hippie.$space_basic;
+ background-color: rgba(0, 0, 0, .1);
+
+ button {
+ @extend .button_io;
+ overflow: hidden;
+ }
+}
+
+#screen-space {
+ position: relative;
+ height: 100%;
+}
+
+#placeholder {
+ display: none;
+ z-index: map.get(hippie.$z-indexes, "content-top");
+ position: fixed;
+ width: 100px;
+ height: 100px;
+ border: 2px dashed deeppink;
+ background-color: hotpink;
+}
\ No newline at end of file
diff --git a/source/style/ui.scss b/source/style/ui.scss
index 4a1e6c8..da6ecf7 100644
--- a/source/style/ui.scss
+++ b/source/style/ui.scss
@@ -9,6 +9,7 @@
@use "modules/ui/form_module";
@use "modules/ui/game_module";
@use "modules/ui/gallery_module";
+@use "modules/ui/windows_module";
$color_gui_back: hippie.$color_dark;
$space_gui_half: hippie.$space_half;