12 CSS Retro UI Designs12 / 12

CSS + JSMIT licensed

Retro Desktop Portfolio Website Template

A classic desktop-OS portfolio: a System-style menu bar with live clock, desktop folder icons, and stacked windows (about / projects / contact) you can drag and bring-to-focus. The chrome — pin-striped title bars, gel close dots, dashed dividers — is pure CSS; focus + drag are tiny vanilla JS. Pixelify Sans + Space Mono on a dotted teal desktop.

Published

Live Demo
Try it

The code

<div class="ret-12">
  <div class="ret-12__menubar">
    <span class="apple">❖</span>
    <span>File</span><span>Edit</span><span>View</span><span>Special</span>
    <span class="spacer"><span>◐ 88%</span><span class="clock" id="ret-12-clock">12:00 PM</span></span>
  </div>

  <div class="ret-12__desk" id="ret-12-desk">
    <div class="ret-12__shortcuts">
      <div class="ret-12__sc"><i>📁</i><span>Work</span></div>
      <div class="ret-12__sc"><i>📄</i><span>Resume</span></div>
      <div class="ret-12__sc"><i>🗑️</i><span>Trash</span></div>
    </div>

    <div class="ret-12__window ret-12__about is-focus" data-win>
      <div class="ret-12__titlebar" data-drag><span class="dot r"></span><span class="dot"></span><b>about_me.txt</b><span class="x">▢</span></div>
      <div class="ret-12__content">
        <div class="ret-12__avatar">🧑‍💻</div>
        <h2>Hi, I'm Mara.<small>// CREATIVE DEVELOPER</small></h2>
        <p>I build playful interfaces with a soft spot for old machines. Drag these windows around — focus &amp; drag are tiny vanilla JS, everything else is pure CSS.</p>
        <div class="ret-12__tags"><span>CSS</span><span>Motion</span><span>WebGL</span><span>Type</span><span>Pixels</span></div>
      </div>
    </div>

    <div class="ret-12__window ret-12__projects" data-win>
      <div class="ret-12__titlebar" data-drag><span class="dot r"></span><span class="dot"></span><b>projects</b><span class="x">▢</span></div>
      <div class="ret-12__content">
        <h2 style="font-size:16px">Selected Work</h2>
        <hr class="ret-12__divider">
        <div class="ret-12__proj"><i>🎨</i><div class="meta"><b>Pixel Painter</b><small>Canvas · 2025</small></div><span class="arrow">→</span></div>
        <div class="ret-12__proj"><i>🎹</i><div class="meta"><b>Synth Web Toy</b><small>WebAudio · 2024</small></div><span class="arrow">→</span></div>
        <div class="ret-12__proj"><i>🌀</i><div class="meta"><b>CRT Shader Lab</b><small>GLSL · 2024</small></div><span class="arrow">→</span></div>
      </div>
    </div>

    <div class="ret-12__window ret-12__contact" data-win>
      <div class="ret-12__titlebar" data-drag><span class="dot r"></span><span class="dot"></span><b>contact</b><span class="x">▢</span></div>
      <div class="ret-12__content">
        <a href="#">→ hello@mara.studio</a>
        <a href="#">→ github.com/mara</a>
        <a href="#">→ dribbble.com/mara</a>
        <a href="#">→ read.cv/mara</a>
      </div>
    </div>

    <div class="ret-12__hint">▲ drag any title bar · click to focus ▲</div>
  </div>
</div>
@import url('https://fonts.googleapis.com/css2?family=Chicago&family=Pixelify+Sans:wght@400;700&family=Space+Mono:wght@400;700&display=swap');

.ret-12,
.ret-12 *,
.ret-12 *::before,
.ret-12 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.ret-12 ::selection {
  background: #000;
  color: #d6f5e3;
}

.ret-12 {
  --bg: #3a6b5e;
  --win: #e8e4d8;
  --ink: #1a1a1a;
  --bar: #1a1a1a;
  --accent: #ff5a3c;
  --accent2: #3c7dff;
  --line: #1a1a1a;
  font-family: 'Space Mono',monospace;
  background: var(--bg);
  background-image: radial-gradient(rgba(255,255,255,.06) 1px,transparent 1px);
  background-size: 6px 6px;
  min-height: 100vh;
  position: relative;
  overflow: hidden;
  color: var(--ink);
  padding: 10px;
}
/* menu bar */

.ret-12__menubar {
  display: flex;
  align-items: center;
  gap: 18px;
  background: var(--win);
  border: 2px solid var(--ink);
  padding: 5px 14px;
  box-shadow: 3px 3px 0 var(--ink);
  font-family: 'Pixelify Sans';
  font-size: 15px;
  position: relative;
  z-index: 100;
}

.ret-12__menubar .apple {
  font-weight: 700;
}

.ret-12__menubar span {
  cursor: default;
}

.ret-12__menubar .spacer {
  margin-left: auto;
  font-size: 13px;
  display: flex;
  gap: 14px;
  align-items: center;
}

.ret-12__menubar .clock {
  font-family: 'Space Mono';
  font-size: 12px;
}

.ret-12__desk {
  position: relative;
  height: calc(100vh - 70px);
  margin-top: 10px;
}
/* desktop folder icons */

.ret-12__shortcuts {
  position: absolute;
  top: 6px;
  right: 6px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  z-index: 1;
}

.ret-12__sc {
  width: 74px;
  text-align: center;
  cursor: pointer;
  color: var(--win);
  text-shadow: 1px 1px 0 #000;
}

.ret-12__sc i {
  display: block;
  font-size: 30px;
  filter: drop-shadow(2px 2px 0 rgba(0,0,0,.4));
}

.ret-12__sc span {
  font-size: 11px;
  font-family: 'Pixelify Sans';
  display: inline-block;
  margin-top: 3px;
  padding: 1px 4px;
}

.ret-12__sc:hover span {
  background: var(--ink);
  color: var(--win);
}
/* windows */

.ret-12__window {
  position: absolute;
  background: var(--win);
  border: 2px solid var(--ink);
  box-shadow: 5px 5px 0 rgba(0,0,0,.5);
  display: flex;
  flex-direction: column;
  min-width: 240px;
}

.ret-12__window.is-focus {
  box-shadow: 7px 7px 0 var(--ink);
  z-index: 50;
}

.ret-12__titlebar {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--bar);
  color: var(--win);
  padding: 5px 8px;
  cursor: grab;
  user-select: none;
}

.ret-12__titlebar.is-drag {
  cursor: grabbing;
}

.ret-12__titlebar .dot {
  width: 13px;
  height: 13px;
  border: 2px solid var(--win);
  border-radius: 50%;
  flex: 0 0 auto;
}

.ret-12__titlebar .dot.r {
  background: var(--accent);
}

.ret-12__titlebar b {
  font-family: 'Pixelify Sans';
  font-size: 14px;
  letter-spacing: .02em;
  flex: 1;
  background: repeating-linear-gradient(var(--win) 0 1px,transparent 1px 3px);
  padding: 2px 8px;
  text-align: center;
  color: var(--win);
}

.ret-12__titlebar .x {
  margin-left: auto;
}

.ret-12__content {
  padding: 16px;
  font-size: 12px;
  line-height: 1.55;
}

.ret-12__content h2 {
  font-family: 'Pixelify Sans';
  font-size: 20px;
  margin-bottom: 4px;
}

.ret-12__content h2 small {
  display: block;
  font-family: 'Space Mono';
  font-size: 11px;
  color: #5a6b64;
  letter-spacing: .1em;
  margin-top: 4px;
}

.ret-12__content p {
  color: #3a3a3a;
}

.ret-12__divider {
  border: 0;
  border-top: 2px dashed var(--ink);
  margin: 12px 0;
}
/* about window */

.ret-12__about {
  width: 300px;
  top: 18px;
  left: 14px;
}

.ret-12__avatar {
  width: 64px;
  height: 64px;
  border: 2px solid var(--ink);
  float: left;
  margin: 0 14px 8px 0;
  background: repeating-conic-gradient(var(--accent) 0 90deg,var(--accent2) 0 180deg) 0 0/16px 16px;
  display: grid;
  place-items: center;
  font-size: 30px;
  background-blend-mode: multiply;
}

.ret-12__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
  clear: both;
}

.ret-12__tags span {
  font-size: 10px;
  border: 1.5px solid var(--ink);
  padding: 3px 7px;
  font-family: 'Pixelify Sans';
}
/* projects window */

.ret-12__projects {
  width: 330px;
  top: 120px;
  left: 230px;
}

@media (max-width: 680px) {
  .ret-12__projects {
    left: 14px;
    top: 300px;
  }
}

.ret-12__proj {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1.5px solid var(--ink);
  padding: 9px;
  margin-bottom: 8px;
  cursor: pointer;
  transition: transform .1s,background .1s;
}

.ret-12__proj:hover {
  transform: translate(-2px,-2px);
  background: #fff;
  box-shadow: 3px 3px 0 var(--ink);
}

.ret-12__proj i {
  font-size: 22px;
}

.ret-12__proj .meta b {
  font-family: 'Pixelify Sans';
  font-size: 13px;
  display: block;
}

.ret-12__proj .meta small {
  font-size: 10px;
  color: #5a6b64;
}

.ret-12__proj .arrow {
  margin-left: auto;
  font-weight: 700;
}
/* contact window */

.ret-12__contact {
  width: 248px;
  top: 330px;
  left: 30px;
}

@media (max-width: 680px) {
  .ret-12__contact {
    display: none;
  }
}

.ret-12__contact a {
  display: block;
  color: var(--accent2);
  text-decoration: none;
  border-bottom: 1px dotted var(--accent2);
  padding: 4px 0;
  font-size: 12px;
}

.ret-12__contact a:hover {
  background: var(--accent2);
  color: #fff;
  padding-left: 6px;
}

.ret-12__hint {
  position: absolute;
  bottom: 6px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 10px;
  color: rgba(255,255,255,.7);
  letter-spacing: .1em;
  z-index: 1;
}

@media (max-width: 680px) {
  .ret-12__about {
    left: 14px;
    width: calc(100% - 60px);
    max-width: 300px;
  }

  .ret-12__shortcuts {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ret-12 * {
    transition: none !important;
  }
}
(() => {
  const root = document.querySelector('.ret-12');
  if (!root) return;
  const desk = root.querySelector('#ret-12-desk');
  const wins = Array.from(root.querySelectorAll('[data-win]'));
  let z = 50;

  function focus(win){
    wins.forEach(w => w.classList.remove('is-focus'));
    win.classList.add('is-focus');
    win.style.zIndex = ++z;
  }
  wins.forEach(win => {
    win.addEventListener('mousedown', () => focus(win), true);
    const bar = win.querySelector('[data-drag]');
    let sx, sy, ox, oy, dragging = false;
    const start = (cx, cy) => {
      dragging = true; focus(win);
      const r = win.getBoundingClientRect();
      const d = desk.getBoundingClientRect();
      ox = r.left - d.left; oy = r.top - d.top; sx = cx; sy = cy;
      win.style.left = ox + 'px'; win.style.top = oy + 'px'; win.style.right = 'auto';
      bar.classList.add('is-drag');
    };
    const move = (cx, cy) => {
      if (!dragging) return;
      let nx = ox + (cx - sx), ny = oy + (cy - sy);
      const d = desk.getBoundingClientRect();
      nx = Math.max(0, Math.min(nx, d.width - 60));
      ny = Math.max(0, Math.min(ny, d.height - 30));
      win.style.left = nx + 'px'; win.style.top = ny + 'px';
    };
    const end = () => { dragging = false; bar.classList.remove('is-drag'); };
    bar.addEventListener('mousedown', e => { e.preventDefault(); start(e.clientX, e.clientY); });
    window.addEventListener('mousemove', e => move(e.clientX, e.clientY));
    window.addEventListener('mouseup', end);
    bar.addEventListener('touchstart', e => { start(e.touches[0].clientX, e.touches[0].clientY); }, {passive:true});
    window.addEventListener('touchmove', e => { if(dragging){ move(e.touches[0].clientX, e.touches[0].clientY); } }, {passive:true});
    window.addEventListener('touchend', end);
  });

  const clock = root.querySelector('#ret-12-clock');
  const tick = () => {
    const d = new Date();
    let h = d.getHours(), m = String(d.getMinutes()).padStart(2,'0');
    const ap = h >= 12 ? 'PM' : 'AM'; h = h % 12 || 12;
    clock.textContent = `${h}:${m} ${ap}`;
  };
  tick(); setInterval(tick, 10000);
})();
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Retro UI Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Retro Desktop Portfolio Website Template
Source: https://codefronts.com/design-styles/css-retro-designs/retro-desktop-portfolio-website-template/

A classic desktop-OS portfolio: a System-style menu bar with live clock, desktop folder icons, and stacked windows (about / projects / contact) you can drag and bring-to-focus. The chrome — pin-striped title bars, gel close dots, dashed dividers — is pure CSS; focus + drag are tiny vanilla JS. Pixelify Sans + Space Mono on a dotted teal desktop.
## HTML
```html
<div class="ret-12">
  <div class="ret-12__menubar">
    <span class="apple">❖</span>
    <span>File</span><span>Edit</span><span>View</span><span>Special</span>
    <span class="spacer"><span>◐ 88%</span><span class="clock" id="ret-12-clock">12:00 PM</span></span>
  </div>

  <div class="ret-12__desk" id="ret-12-desk">
    <div class="ret-12__shortcuts">
      <div class="ret-12__sc"><i>📁</i><span>Work</span></div>
      <div class="ret-12__sc"><i>📄</i><span>Resume</span></div>
      <div class="ret-12__sc"><i>🗑️</i><span>Trash</span></div>
    </div>

    <div class="ret-12__window ret-12__about is-focus" data-win>
      <div class="ret-12__titlebar" data-drag><span class="dot r"></span><span class="dot"></span><b>about_me.txt</b><span class="x">▢</span></div>
      <div class="ret-12__content">
        <div class="ret-12__avatar">🧑‍💻</div>
        <h2>Hi, I'm Mara.<small>// CREATIVE DEVELOPER</small></h2>
        <p>I build playful interfaces with a soft spot for old machines. Drag these windows around — focus &amp; drag are tiny vanilla JS, everything else is pure CSS.</p>
        <div class="ret-12__tags"><span>CSS</span><span>Motion</span><span>WebGL</span><span>Type</span><span>Pixels</span></div>
      </div>
    </div>

    <div class="ret-12__window ret-12__projects" data-win>
      <div class="ret-12__titlebar" data-drag><span class="dot r"></span><span class="dot"></span><b>projects</b><span class="x">▢</span></div>
      <div class="ret-12__content">
        <h2 style="font-size:16px">Selected Work</h2>
        <hr class="ret-12__divider">
        <div class="ret-12__proj"><i>🎨</i><div class="meta"><b>Pixel Painter</b><small>Canvas · 2025</small></div><span class="arrow">→</span></div>
        <div class="ret-12__proj"><i>🎹</i><div class="meta"><b>Synth Web Toy</b><small>WebAudio · 2024</small></div><span class="arrow">→</span></div>
        <div class="ret-12__proj"><i>🌀</i><div class="meta"><b>CRT Shader Lab</b><small>GLSL · 2024</small></div><span class="arrow">→</span></div>
      </div>
    </div>

    <div class="ret-12__window ret-12__contact" data-win>
      <div class="ret-12__titlebar" data-drag><span class="dot r"></span><span class="dot"></span><b>contact</b><span class="x">▢</span></div>
      <div class="ret-12__content">
        <a href="#">→ hello@mara.studio</a>
        <a href="#">→ github.com/mara</a>
        <a href="#">→ dribbble.com/mara</a>
        <a href="#">→ read.cv/mara</a>
      </div>
    </div>

    <div class="ret-12__hint">▲ drag any title bar · click to focus ▲</div>
  </div>
</div>
```
## CSS
```css
@import url('https://fonts.googleapis.com/css2?family=Chicago&family=Pixelify+Sans:wght@400;700&family=Space+Mono:wght@400;700&display=swap');

.ret-12,
.ret-12 *,
.ret-12 *::before,
.ret-12 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.ret-12 ::selection {
  background: #000;
  color: #d6f5e3;
}

.ret-12 {
  --bg: #3a6b5e;
  --win: #e8e4d8;
  --ink: #1a1a1a;
  --bar: #1a1a1a;
  --accent: #ff5a3c;
  --accent2: #3c7dff;
  --line: #1a1a1a;
  font-family: 'Space Mono',monospace;
  background: var(--bg);
  background-image: radial-gradient(rgba(255,255,255,.06) 1px,transparent 1px);
  background-size: 6px 6px;
  min-height: 100vh;
  position: relative;
  overflow: hidden;
  color: var(--ink);
  padding: 10px;
}
/* menu bar */

.ret-12__menubar {
  display: flex;
  align-items: center;
  gap: 18px;
  background: var(--win);
  border: 2px solid var(--ink);
  padding: 5px 14px;
  box-shadow: 3px 3px 0 var(--ink);
  font-family: 'Pixelify Sans';
  font-size: 15px;
  position: relative;
  z-index: 100;
}

.ret-12__menubar .apple {
  font-weight: 700;
}

.ret-12__menubar span {
  cursor: default;
}

.ret-12__menubar .spacer {
  margin-left: auto;
  font-size: 13px;
  display: flex;
  gap: 14px;
  align-items: center;
}

.ret-12__menubar .clock {
  font-family: 'Space Mono';
  font-size: 12px;
}

.ret-12__desk {
  position: relative;
  height: calc(100vh - 70px);
  margin-top: 10px;
}
/* desktop folder icons */

.ret-12__shortcuts {
  position: absolute;
  top: 6px;
  right: 6px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  z-index: 1;
}

.ret-12__sc {
  width: 74px;
  text-align: center;
  cursor: pointer;
  color: var(--win);
  text-shadow: 1px 1px 0 #000;
}

.ret-12__sc i {
  display: block;
  font-size: 30px;
  filter: drop-shadow(2px 2px 0 rgba(0,0,0,.4));
}

.ret-12__sc span {
  font-size: 11px;
  font-family: 'Pixelify Sans';
  display: inline-block;
  margin-top: 3px;
  padding: 1px 4px;
}

.ret-12__sc:hover span {
  background: var(--ink);
  color: var(--win);
}
/* windows */

.ret-12__window {
  position: absolute;
  background: var(--win);
  border: 2px solid var(--ink);
  box-shadow: 5px 5px 0 rgba(0,0,0,.5);
  display: flex;
  flex-direction: column;
  min-width: 240px;
}

.ret-12__window.is-focus {
  box-shadow: 7px 7px 0 var(--ink);
  z-index: 50;
}

.ret-12__titlebar {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--bar);
  color: var(--win);
  padding: 5px 8px;
  cursor: grab;
  user-select: none;
}

.ret-12__titlebar.is-drag {
  cursor: grabbing;
}

.ret-12__titlebar .dot {
  width: 13px;
  height: 13px;
  border: 2px solid var(--win);
  border-radius: 50%;
  flex: 0 0 auto;
}

.ret-12__titlebar .dot.r {
  background: var(--accent);
}

.ret-12__titlebar b {
  font-family: 'Pixelify Sans';
  font-size: 14px;
  letter-spacing: .02em;
  flex: 1;
  background: repeating-linear-gradient(var(--win) 0 1px,transparent 1px 3px);
  padding: 2px 8px;
  text-align: center;
  color: var(--win);
}

.ret-12__titlebar .x {
  margin-left: auto;
}

.ret-12__content {
  padding: 16px;
  font-size: 12px;
  line-height: 1.55;
}

.ret-12__content h2 {
  font-family: 'Pixelify Sans';
  font-size: 20px;
  margin-bottom: 4px;
}

.ret-12__content h2 small {
  display: block;
  font-family: 'Space Mono';
  font-size: 11px;
  color: #5a6b64;
  letter-spacing: .1em;
  margin-top: 4px;
}

.ret-12__content p {
  color: #3a3a3a;
}

.ret-12__divider {
  border: 0;
  border-top: 2px dashed var(--ink);
  margin: 12px 0;
}
/* about window */

.ret-12__about {
  width: 300px;
  top: 18px;
  left: 14px;
}

.ret-12__avatar {
  width: 64px;
  height: 64px;
  border: 2px solid var(--ink);
  float: left;
  margin: 0 14px 8px 0;
  background: repeating-conic-gradient(var(--accent) 0 90deg,var(--accent2) 0 180deg) 0 0/16px 16px;
  display: grid;
  place-items: center;
  font-size: 30px;
  background-blend-mode: multiply;
}

.ret-12__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
  clear: both;
}

.ret-12__tags span {
  font-size: 10px;
  border: 1.5px solid var(--ink);
  padding: 3px 7px;
  font-family: 'Pixelify Sans';
}
/* projects window */

.ret-12__projects {
  width: 330px;
  top: 120px;
  left: 230px;
}

@media (max-width: 680px) {
  .ret-12__projects {
    left: 14px;
    top: 300px;
  }
}

.ret-12__proj {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1.5px solid var(--ink);
  padding: 9px;
  margin-bottom: 8px;
  cursor: pointer;
  transition: transform .1s,background .1s;
}

.ret-12__proj:hover {
  transform: translate(-2px,-2px);
  background: #fff;
  box-shadow: 3px 3px 0 var(--ink);
}

.ret-12__proj i {
  font-size: 22px;
}

.ret-12__proj .meta b {
  font-family: 'Pixelify Sans';
  font-size: 13px;
  display: block;
}

.ret-12__proj .meta small {
  font-size: 10px;
  color: #5a6b64;
}

.ret-12__proj .arrow {
  margin-left: auto;
  font-weight: 700;
}
/* contact window */

.ret-12__contact {
  width: 248px;
  top: 330px;
  left: 30px;
}

@media (max-width: 680px) {
  .ret-12__contact {
    display: none;
  }
}

.ret-12__contact a {
  display: block;
  color: var(--accent2);
  text-decoration: none;
  border-bottom: 1px dotted var(--accent2);
  padding: 4px 0;
  font-size: 12px;
}

.ret-12__contact a:hover {
  background: var(--accent2);
  color: #fff;
  padding-left: 6px;
}

.ret-12__hint {
  position: absolute;
  bottom: 6px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 10px;
  color: rgba(255,255,255,.7);
  letter-spacing: .1em;
  z-index: 1;
}

@media (max-width: 680px) {
  .ret-12__about {
    left: 14px;
    width: calc(100% - 60px);
    max-width: 300px;
  }

  .ret-12__shortcuts {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ret-12 * {
    transition: none !important;
  }
}
```

## JavaScript
```js
(() => {
  const root = document.querySelector('.ret-12');
  if (!root) return;
  const desk = root.querySelector('#ret-12-desk');
  const wins = Array.from(root.querySelectorAll('[data-win]'));
  let z = 50;

  function focus(win){
    wins.forEach(w => w.classList.remove('is-focus'));
    win.classList.add('is-focus');
    win.style.zIndex = ++z;
  }
  wins.forEach(win => {
    win.addEventListener('mousedown', () => focus(win), true);
    const bar = win.querySelector('[data-drag]');
    let sx, sy, ox, oy, dragging = false;
    const start = (cx, cy) => {
      dragging = true; focus(win);
      const r = win.getBoundingClientRect();
      const d = desk.getBoundingClientRect();
      ox = r.left - d.left; oy = r.top - d.top; sx = cx; sy = cy;
      win.style.left = ox + 'px'; win.style.top = oy + 'px'; win.style.right = 'auto';
      bar.classList.add('is-drag');
    };
    const move = (cx, cy) => {
      if (!dragging) return;
      let nx = ox + (cx - sx), ny = oy + (cy - sy);
      const d = desk.getBoundingClientRect();
      nx = Math.max(0, Math.min(nx, d.width - 60));
      ny = Math.max(0, Math.min(ny, d.height - 30));
      win.style.left = nx + 'px'; win.style.top = ny + 'px';
    };
    const end = () => { dragging = false; bar.classList.remove('is-drag'); };
    bar.addEventListener('mousedown', e => { e.preventDefault(); start(e.clientX, e.clientY); });
    window.addEventListener('mousemove', e => move(e.clientX, e.clientY));
    window.addEventListener('mouseup', end);
    bar.addEventListener('touchstart', e => { start(e.touches[0].clientX, e.touches[0].clientY); }, {passive:true});
    window.addEventListener('touchmove', e => { if(dragging){ move(e.touches[0].clientX, e.touches[0].clientY); } }, {passive:true});
    window.addEventListener('touchend', end);
  });

  const clock = root.querySelector('#ret-12-clock');
  const tick = () => {
    const d = new Date();
    let h = d.getHours(), m = String(d.getMinutes()).padStart(2,'0');
    const ap = h >= 12 ? 'PM' : 'AM'; h = h % 12 || 12;
    clock.textContent = `${h}:${m} ${ap}`;
  };
  tick(); setInterval(tick, 10000);
})();
```

Techniques used in this demo

Search CodeFronts

Loading…