Skip to content

Lightweight 3D text library with depth and interactive rotation. High performance, dependency-free, modern ES module.

License

Notifications You must be signed in to change notification settings

mobiwise-dev/DepthText

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

8 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Animation

DepthText.js

npm version npm downloads bundle size jsdelivr hits GitHub license GitHub stars

DepthText is a lightweight, dependency-free JavaScript library that creates smooth multi-layer 3D text with depth, parallax, and interactive rotation.
Designed for high performance, accessibility, and modern UX motion guidelines.

It is the spiritual successor of ztext.js, but rewritten from scratch with a cleaner API, better performance, and a modern ES module architecture.


✨ Features

  • πŸŒ€ True 3D layered depth using CSS transform-style: preserve-3d
  • πŸ–±οΈ Interactive rotation (auto, pointer, scroll…)
  • 🎚️ Configurable number of layers
  • 🎨 Optional fade effect across layers
  • ⚑ GPU-optimized and jank-free
  • 🦾 Accessibility-friendly (aria-hidden, reduced-motion support)
  • πŸ”₯ No dependencies, only 4–6 KB minified
  • πŸ“¦ Works with bundlers, ES modules, and browsers
  • πŸ–ΌοΈ Supports images, SVGs, and emojis within text content
  • 🎭 Custom CSS classes for advanced styling control
  • 🎨 Per-layer styling with layerClassMap and auto-generated classes
  • πŸ”„ Dynamic updates with .update() method

πŸ›  Installation

NPM

npm install depthtext

CDN

jsDelivr (Recommended)

<!-- ESM -->
<script type="module">
  import { DepthTextify } from "https://cdn.jsdelivr.net/npm/depthtext@latest/dist/depthtext.mjs";
  DepthTextify();
</script>

<!-- Global/IIFE (classic script tag) -->
<script src="https://cdn.jsdelivr.net/npm/depthtext@latest/dist/depthtext.global.js"></script>
<script>
  DepthText.DepthTextify();
</script>

unpkg

<!-- ESM -->
<script type="module">
  import { DepthTextify } from "https://unpkg.com/depthtext@latest/dist/depthtext.mjs";
  DepthTextify();
</script>

<!-- Global/IIFE -->
<script src="https://unpkg.com/depthtext@latest/dist/depthtext.global.js"></script>
<script>
  DepthText.DepthTextify();
</script>

Import (ES module)

import { DepthTextify } from "depthtext";

πŸš€ Quick Start

HTML

<h1 class="depthtext" data-depth="2rem" data-depth-event="pointer">DepthText Rocks</h1>

JavaScript

import { DepthTextify } from "depthtext";

DepthTextify(); // Enhances all elements with [data-depth]

🧩 Options

DepthText can be configured using either:

  • HTML data attributes
  • or JavaScript options

HTML Attributes

Attribute Type Default Description
data-depth string 1rem Z-axis distance between layers (e.g., "2rem", "20px")
data-depth-layers number 10 Number of 3D layers (1-40, recommended ≀25 for performance)
data-depth-direction string both Layer direction: both, forwards, backwards
data-depth-event string none Interaction: none, pointer, scroll, scrollX, scrollY
data-depth-event-rotation string 30deg Max rotation angle on interaction (e.g., "45deg", "0.5rad")
data-depth-event-direction string default Rotation direction: default, reverse
data-depth-fade boolean false Fade layers as depth increases
data-depth-perspective string 500px CSS perspective value
data-depth-engaged boolean true Enable/disable the effect
data-depth-add-class string "" Custom CSS class(es) to add to ALL layers

⚠️ Important: Use data-depth-engaged to enable/disable, NOT data-depth alone.


JavaScript API

import { DepthTextInstance } from "depthtext";

const instance = new DepthTextInstance(element, {
  depth: "1rem", // Z-distance between layers
  layers: 10, // Number of layers
  direction: "both", // "both" | "forwards" | "backwards"
  event: "pointer", // "none" | "pointer" | "scroll" | "scrollX" | "scrollY"
  eventRotation: "30deg", // Max tilt angle
  eventDirection: "default", // "default" | "reverse"
  fade: false, // Enable opacity fade
  perspective: "500px", // CSS perspective
  engaged: true, // Enable/disable effect
  addClass: "my-class", // Custom class for ALL layers
  layerClassMap: ["front", "middle", "back"], // Custom class per layer (NEW in v1.2.0)
});

// Dynamically update options (NEW in v1.2.0)
instance.update({
  depth: "2rem",
  event: "scroll",
});

// Cleanup
instance.destroy();

🎨 Advanced Styling

Auto-Generated Layer Classes (NEW in v1.2.0)

Each layer automatically receives a unique class:

<!-- 3 layers example -->
<span class="depthtext-layer depthtext-layer-0">...</span>
<span class="depthtext-layer depthtext-layer-1">...</span>
<span class="depthtext-layer depthtext-layer-2">...</span>

Target specific layers with CSS:

.depthtext-layer-0 {
  /* Front layer */
}
.depthtext-layer-1 {
  /* Middle layer */
}
.depthtext-layer-2 {
  /* Back layer */
}

Per-Layer Custom Classes with layerClassMap (NEW in v1.2.0)

Map custom classes to individual layers by index:

new DepthTextInstance(element, {
  layers: 5,
  layerClassMap: ["front", "mid-front", "center", "mid-back", "back"],
});

Result:

<span class="depthtext-layer depthtext-layer-0 front">...</span>
<span class="depthtext-layer depthtext-layer-1 mid-front">...</span>
<span class="depthtext-layer depthtext-layer-2 center">...</span>
<span class="depthtext-layer depthtext-layer-3 mid-back">...</span>
<span class="depthtext-layer depthtext-layer-4 back">...</span>

Rainbow gradient example:

new DepthTextInstance(element, {
  layers: 7,
  layerClassMap: ["red", "orange", "yellow", "green", "blue", "indigo", "violet"],
});
.red {
  color: #ff0000;
}
.orange {
  color: #ff7f00;
}
.yellow {
  color: #ffff00;
}
.green {
  color: #00ff00;
}
.blue {
  color: #0000ff;
}
.indigo {
  color: #4b0082;
}
.violet {
  color: #9400d3;
}

⚠️ Partial mapping: If you provide fewer classes than layers, unmapped layers will only receive default classes:

new DepthTextInstance(element, {
  layers: 10,
  layerClassMap: ["special-0", "special-1", "special-2"],
  // Layers 3-9 will only have: depthtext-layer depthtext-layer-N
});

Apply Classes to ALL Layers with addClass

<h1 data-depth="1rem" data-depth-add-class="gradient-text">Stylized Text</h1>
.gradient-text {
  background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

Multiple classes:

new DepthTextInstance(element, {
  addClass: "gradient-text shadow-effect animated",
});

🎯 Important: Styling Individual Layer Colors

Because layers are clones sharing the same text formatting context, color inheritance can be tricky.

❌ This WON'T work reliably:

.depthtext-layer-0 {
  color: blue;
}
.depthtext-layer-1 {
  color: red;
}

βœ… Use the universal selector instead:

.depthtext-layer-0 * {
  color: blue !important;
}
.depthtext-layer-1 * {
  color: red !important;
}

Or add a global reset:

.depthtext-layer > * {
  color: inherit !important;
}

This ensures each layer's content truly inherits its parent layer's color.

Advanced Styling Examples

/* Neon glow effect */
.neon-glow {
  color: #00ffff;
  text-shadow: 0 0 10px #00ffff, 0 0 20px #00ffff, 0 0 30px #00ffff;
}

/* Metallic gradient */
.metallic {
  background: linear-gradient(90deg, #c0c0c0, #e8e8e8, #c0c0c0);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

/* Rainbow animation */
@keyframes rainbow {
  0%,
  100% {
    color: #ff0000;
  }
  16% {
    color: #ff7f00;
  }
  33% {
    color: #ffff00;
  }
  50% {
    color: #00ff00;
  }
  66% {
    color: #0000ff;
  }
  83% {
    color: #8b00ff;
  }
}

.rainbow-text {
  animation: rainbow 3s linear infinite;
}

/* Per-layer depth-based opacity */
.depthtext-layer-0 {
  opacity: 1;
}
.depthtext-layer-1 {
  opacity: 0.9;
}
.depthtext-layer-2 {
  opacity: 0.8;
}
.depthtext-layer-3 {
  opacity: 0.7;
}

πŸ”„ Dynamic Updates (NEW in v1.2.0)

Change options after initialization without recreating the instance:

const instance = new DepthTextInstance(element, {
  depth: "1rem",
  event: "pointer",
});

// Later, change behavior
instance.update({
  depth: "2rem",
  event: "scroll",
  layers: 15,
});

Perfect for:

  • Responsive designs (change depth on mobile)
  • Interactive controls (user preferences)
  • State-based animations

🌐 Automatic Initialization

Auto-enhance all elements with [data-depth] attribute:

<h1 data-depth="2rem" data-depth-event="pointer">Auto-enhanced</h1>
<h2 data-depth="1rem" data-depth-layers="5">Another one</h2>
import { DepthTextify } from "depthtext";

// Initialize all [data-depth] elements
DepthTextify();

// Or with custom selector
DepthTextify(".custom-selector");

// Or with default options
DepthTextify({
  depth: "2rem",
  event: "pointer",
});

🧼 Accessibility

DepthText is designed to remain invisible to assistive technologies:

  • Wrappers are automatically marked with aria-hidden="true"
  • Motion reacts to prefers-reduced-motion: reduce
  • Original text remains intact and readable in source
  • Screen readers only see the original content

πŸ“¦ Browser Usage (no bundler)

<script src="dist/depthtext.global.js"></script>
<script>
  // DepthText is available globally
  DepthText.DepthTextify();
</script>

βš›οΈ Framework Integration

DepthText is framework-agnostic. You can use it with React, Vue, Angular, Svelte, etc., by instantiating DepthTextInstance on a mounted DOM element.

React / Next.js

import { useEffect, useRef } from "react";
import { DepthTextInstance } from "depthtext";

export default function DepthComponent() {
  const textRef = useRef(null);

  useEffect(() => {
    if (!textRef.current) return;

    const dt = new DepthTextInstance(textRef.current, {
      layers: 10,
      depth: "1rem",
      event: "pointer",
      layerClassMap: ["front", "mid", "back"], // Per-layer styling
    });

    // Cleanup on unmount
    return () => dt.destroy();
  }, []);

  return <h1 ref={textRef}>DepthText in React</h1>;
}

Vue 3

<script setup>
  import { onMounted, onUnmounted, ref } from "vue";
  import { DepthTextInstance } from "depthtext";

  const textRef = ref(null);
  let dt = null;

  onMounted(() => {
    if (textRef.value) {
      dt = new DepthTextInstance(textRef.value, {
        layers: 10,
        event: "pointer",
        addClass: "custom-style",
        layerClassMap: ["layer-a", "layer-b", "layer-c"],
      });
    }
  });

  onUnmounted(() => {
    if (dt) dt.destroy();
  });
</script>

<template>
  <h1 ref="textRef">DepthText in Vue</h1>
</template>

Angular

import { Component, ElementRef, ViewChild, AfterViewInit, OnDestroy } from "@angular/core";
import { DepthTextInstance } from "depthtext";

@Component({
  selector: "app-depth-text",
  template: "<h1 #depthText>DepthText in Angular</h1>",
})
export class DepthTextComponent implements AfterViewInit, OnDestroy {
  @ViewChild("depthText") textRef!: ElementRef;
  private dt?: DepthTextInstance;

  ngAfterViewInit() {
    this.dt = new DepthTextInstance(this.textRef.nativeElement, {
      layers: 10,
      event: "pointer",
      layerClassMap: ["front", "middle", "back"],
    });
  }

  ngOnDestroy() {
    this.dt?.destroy();
  }
}

🎭 Supported Content

DepthText works with various content types:

βœ… Fully Supported

  • Text content (including unicode, special characters)
  • Emojis (😊, πŸš€, ❀️, etc.)
  • Inline SVG (<svg>...</svg>)
  • Images (<img src="...">)
  • Mixed content (text + images + SVGs together)

Example with mixed content:

<h1 class="depthtext" data-depth="1rem" data-depth-event="pointer" data-depth-add-class="colorful">
  Hello World! πŸš€
  <svg width="30" height="30"><circle cx="15" cy="15" r="10" fill="blue" /></svg>
  <img src="logo.png" width="40" alt="Logo" />
</h1>

⚠️ Notes

  • Images should be loaded before initialization for best results
  • Very large images may impact performance
  • External SVGs (<img src="icon.svg">) work like regular images

πŸ›  Known Issues & Notes

  • DepthText uses CSS transforms; parent elements must not flatten 3D contexts
  • Avoid nested DepthText unless you understand transform-style: preserve-3d
  • Images: For complex layouts, consider using background-image on wrapper elements
  • Performance: Very high layer counts (>25) with large images may impact performance
  • Color styling: Use .depthtext-layer-N * { color: ... } for reliable per-layer coloring

πŸ§‘β€πŸ’» Contributing

Pull requests are welcome!
If you add a major feature, please include documentation updates.


πŸ“„ License

MIT License – free to use in commercial and open-source projects.


πŸ’¬ Author

Created by MobiWise.
A modern reimagining of the classic ztext.js.

About

Lightweight 3D text library with depth and interactive rotation. High performance, dependency-free, modern ES module.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published