3D Environment Loader – Ash Technical
<div class="fp-vr-3d-environment-loading-ui">
<div class="fp-vr-3d-environment-loading-ui-container">
<div class="fp-vr-3d-environment-loading-ui-stage">
<div class="fp-vr-3d-environment-loading-ui-grid"></div>
<div class="fp-vr-3d-environment-loading-ui-glow"></div>
<div class="fp-vr-3d-environment-loading-ui-tunnel">
<div class="fp-vr-3d-environment-loading-ui-ring"></div>
<div class="fp-vr-3d-environment-loading-ui-ring"></div>
<div class="fp-vr-3d-environment-loading-ui-ring"></div>
</div>
<canvas class="fp-vr-3d-environment-loading-ui-canvas"></canvas>
<div class="fp-vr-3d-environment-loading-ui-reticle"></div>
<div class="fp-vr-3d-environment-loading-ui-panel">
<div class="fp-vr-3d-environment-loading-ui-status-box">
<div class="fp-vr-3d-environment-loading-ui-status-header">
<div class="fp-vr-3d-environment-loading-ui-dot"></div>
<span class="fp-vr-3d-environment-loading-ui-label">ENV. CONSTRUCT</span>
</div>
<span class="fp-vr-3d-environment-loading-ui-sub-label">Mapping Vector Space</span>
</div>
<div class="fp-vr-3d-environment-loading-ui-progress">0%</div>
</div>
</div>
</div>
</div>.fp-vr-3d-environment-loading-ui {
--fp-container-width: 100%;
--fp-max-width: 500px;
--fp-aspect-ratio: 1 / 1;
--fp-primary-color: #f5f6f8;
--fp-secondary-color: #d1d4d9;
--fp-muted-color: #8c9199;
--fp-soft-color: #e5e7eb;
--fp-background-color: transparent;
--fp-info-color: #717680;
--fp-warning-color: #4a4d54;
--fp-danger-color: #1a1c1e;
--fp-accent-color: #5a5e66;
--fp-text-color: #2b2d31;
display: flex;
justify-content: center;
width: var(--fp-container-width);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
.fp-vr-3d-environment-loading-ui-container {
width: 100%;
max-width: var(--fp-max-width);
background-color: var(--fp-background-color);
}
.fp-vr-3d-environment-loading-ui-stage {
aspect-ratio: var(--fp-aspect-ratio);
background-color: var(--fp-primary-color);
border: 1px solid var(--fp-secondary-color);
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05), inset 0 0 60px rgba(0,0,0,0.02);
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.fp-vr-3d-environment-loading-ui-grid {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
linear-gradient(var(--fp-secondary-color) 1px, transparent 1px),
linear-gradient(90deg, var(--fp-secondary-color) 1px, transparent 1px);
background-size: 20px 20px;
background-position: center center;
opacity: 0.4;
z-index: 0;
pointer-events: none;
}
.fp-vr-3d-environment-loading-ui-glow {
position: absolute;
width: 80%;
height: 80%;
background: radial-gradient(circle, rgba(90, 94, 102, 0.08) 0%, transparent 70%);
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
animation: fp-vr-3d-environment-loading-ui-breathe 4s ease-in-out infinite;
z-index: 1;
pointer-events: none;
}
.fp-vr-3d-environment-loading-ui-tunnel {
position: absolute;
top: 50%;
left: 50%;
width: 100px;
height: 100px;
transform: translate(-50%, -50%);
perspective: 800px;
z-index: 2;
}
.fp-vr-3d-environment-loading-ui-ring {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 1px solid var(--fp-muted-color);
border-radius: 4px;
opacity: 0;
animation: fp-vr-3d-environment-loading-ui-zoom 6s linear infinite;
transform-origin: center center;
}
.fp-vr-3d-environment-loading-ui-ring:nth-child(2) { animation-delay: -2s; }
.fp-vr-3d-environment-loading-ui-ring:nth-child(3) { animation-delay: -4s; }
.fp-vr-3d-environment-loading-ui-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 3;
pointer-events: none;
}
.fp-vr-3d-environment-loading-ui-reticle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
border: 1px dashed var(--fp-accent-color);
border-radius: 50%;
z-index: 4;
display: flex;
align-items: center;
justify-content: center;
animation: fp-vr-3d-environment-loading-ui-spin-slow 10s linear infinite;
}
.fp-vr-3d-environment-loading-ui-reticle::before,
.fp-vr-3d-environment-loading-ui-reticle::after {
content: '';
position: absolute;
background-color: var(--fp-accent-color);
}
.fp-vr-3d-environment-loading-ui-reticle::before { width: 10px; height: 1px; }
.fp-vr-3d-environment-loading-ui-reticle::after { height: 10px; width: 1px; }
.fp-vr-3d-environment-loading-ui-panel {
position: absolute;
bottom: 24px;
left: 24px;
right: 24px;
display: flex;
justify-content: space-between;
align-items: flex-end;
z-index: 5;
pointer-events: none;
}
.fp-vr-3d-environment-loading-ui-status-box {
display: flex;
flex-direction: column;
gap: 6px;
}
.fp-vr-3d-environment-loading-ui-status-header {
display: flex;
align-items: center;
gap: 8px;
}
.fp-vr-3d-environment-loading-ui-dot {
width: 6px;
height: 6px;
background-color: var(--fp-text-color);
border-radius: 50%;
animation: fp-vr-3d-environment-loading-ui-blink 1.5s infinite;
}
.fp-vr-3d-environment-loading-ui-label {
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 1px;
color: var(--fp-text-color);
text-transform: uppercase;
}
.fp-vr-3d-environment-loading-ui-sub-label {
font-size: 0.6rem;
color: var(--fp-muted-color);
letter-spacing: 0.5px;
}
.fp-vr-3d-environment-loading-ui-progress {
font-size: 2.5rem;
font-weight: 300;
line-height: 1;
color: var(--fp-text-color);
letter-spacing: -1px;
}
@keyframes fp-vr-3d-environment-loading-ui-breathe {
0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.6; }
50% { transform: translate(-50%, -50%) scale(1.15); opacity: 1; }
}
@keyframes fp-vr-3d-environment-loading-ui-zoom {
0% { transform: scale(0.05) translateZ(-500px); opacity: 0; border-width: 1px; }
20% { opacity: 0.8; border-width: 2px; }
80% { opacity: 0.8; border-width: 1px; }
100% { transform: scale(5) translateZ(200px); opacity: 0; border-width: 0.5px; }
}
@keyframes fp-vr-3d-environment-loading-ui-spin-slow {
0% { transform: translate(-50%, -50%) rotate(0deg); }
100% { transform: translate(-50%, -50%) rotate(360deg); }
}
@keyframes fp-vr-3d-environment-loading-ui-blink {
0%, 100% { opacity: 1; box-shadow: 0 0 5px var(--fp-text-color); }
50% { opacity: 0.3; box-shadow: 0 0 0 transparent; }
}
@media (max-width: 480px) {
.fp-vr-3d-environment-loading-ui-panel { bottom: 16px; left: 16px; right: 16px; }
.fp-vr-3d-environment-loading-ui-progress { font-size: 2rem; }
.fp-vr-3d-environment-loading-ui-label { font-size: 0.6rem; }
}document.querySelectorAll('.fp-vr-3d-environment-loading-ui').forEach(root => {
const canvas = root.querySelector('.fp-vr-3d-environment-loading-ui-canvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
const progressEl = root.querySelector('.fp-vr-3d-environment-loading-ui-progress');
const subLabelEl = root.querySelector('.fp-vr-3d-environment-loading-ui-sub-label');
let animationFrameId;
let isRunning = false;
let width, height, cx, cy;
let progress = 0;
const fov = 250;
const vertices = [];
const maxDepth = 1000;
const numVertices = 60;
const accentColor = '#5a5e66';
const textColor = '#2b2d31';
const mutedColor = '#8c9199';
const statuses = [
"Mapping Vector Space",
"Generating Topography",
"Calculating Depth Buffer",
"Rendering Wireframes",
"Initializing Physics"
];
function fp_vr_3d_environment_loading_ui_resize() {
if (!canvas.parentElement) return;
const rect = canvas.parentElement.getBoundingClientRect();
width = rect.width;
height = rect.height;
canvas.width = width * window.devicePixelRatio;
canvas.height = height * window.devicePixelRatio;
ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
cx = width / 2;
cy = height / 2;
}
class fp_vr_Vertex {
constructor() {
this.reset(true);
}
reset(randomZ = false) {
this.x = (Math.random() - 0.5) * width * 2;
this.y = (Math.random() - 0.5) * height * 2;
this.z = randomZ ? Math.random() * maxDepth : maxDepth;
this.speed = 1.5 + Math.random() * 2;
this.isNode = Math.random() > 0.8;
}
update() {
this.z -= this.speed;
if (this.z <= 0) {
this.reset();
}
}
project() {
const scale = fov / (fov + this.z);
const px = (this.x * scale) + cx;
const py = (this.y * scale) + cy;
return { px, py, scale };
}
}
function fp_vr_3d_environment_loading_ui_init() {
vertices.length = 0;
for (let i = 0; i < numVertices; i++) {
vertices.push(new fp_vr_Vertex());
}
}
function fp_vr_3d_environment_loading_ui_loop() {
if (!isRunning) return;
ctx.clearRect(0, 0, width, height);
progress += 0.15;
if (progress > 100) progress = 0;
progressEl.textContent = Math.floor(progress) + '%';
if (Math.floor(progress) % 25 === 0 && Math.floor(progress) !== 0) {
const idx = Math.floor((progress / 100) * statuses.length) % statuses.length;
subLabelEl.textContent = statuses[idx];
}
ctx.lineWidth = 0.5;
for (let i = 0; i < vertices.length; i++) {
vertices[i].update();
const p1 = vertices[i].project();
const alpha = 1 - (vertices[i].z / maxDepth);
ctx.beginPath();
ctx.arc(p1.px, p1.py, vertices[i].isNode ? 2.5 * p1.scale : 1 * p1.scale, 0, Math.PI * 2);
ctx.fillStyle = vertices[i].isNode ? textColor : accentColor;
ctx.globalAlpha = alpha;
ctx.fill();
for (let j = i + 1; j < vertices.length; j++) {
const dist = Math.hypot(vertices[i].x - vertices[j].x, vertices[i].y - vertices[j].y);
if (dist < 150) {
const p2 = vertices[j].project();
ctx.beginPath();
ctx.moveTo(p1.px, p1.py);
ctx.lineTo(p2.px, p2.py);
ctx.strokeStyle = mutedColor;
ctx.globalAlpha = alpha * 0.3;
ctx.stroke();
}
}
}
ctx.globalAlpha = 1;
const scanY = (Date.now() / 15) % height;
ctx.fillStyle = accentColor;
ctx.globalAlpha = 0.15;
ctx.fillRect(0, scanY, width, 2);
ctx.globalAlpha = 1;
animationFrameId = requestAnimationFrame(fp_vr_3d_environment_loading_ui_loop);
}
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
if (!isRunning && document.visibilityState !== "hidden") {
isRunning = true;
fp_vr_3d_environment_loading_ui_loop();
}
} else {
isRunning = false;
cancelAnimationFrame(animationFrameId);
}
});
});
function fp_vr_3d_environment_loading_ui_handleVisibility() {
if (document.visibilityState === "hidden") {
isRunning = false;
cancelAnimationFrame(animationFrameId);
} else if (!isRunning && root.getBoundingClientRect().top < window.innerHeight && root.getBoundingClientRect().bottom > 0) {
isRunning = true;
fp_vr_3d_environment_loading_ui_loop();
}
}
function fp_vr_3d_environment_loading_ui_checkDOM() {
if (!document.body.contains(root)) {
isRunning = false;
cancelAnimationFrame(animationFrameId);
window.removeEventListener('resize', fp_vr_3d_environment_loading_ui_resize);
document.removeEventListener('visibilitychange', fp_vr_3d_environment_loading_ui_handleVisibility);
observer.disconnect();
return true;
}
return false;
}
window.addEventListener('resize', fp_vr_3d_environment_loading_ui_resize);
document.addEventListener('visibilitychange', fp_vr_3d_environment_loading_ui_handleVisibility);
fp_vr_3d_environment_loading_ui_resize();
fp_vr_3d_environment_loading_ui_init();
observer.observe(root);
const cleanupInterval = setInterval(() => {
if (fp_vr_3d_environment_loading_ui_checkDOM()) {
clearInterval(cleanupInterval);
}
}, 2000);
});Description
Let us look at the 3D Environment Loader Ash Technical component. This free UI asset offers a modular card system specifically engineered for the virtual reality and augmented reality sector. We built this entirely from scratch to handle heavy 3D asset staging without the usual framework bloat. You get a sterile DOM structure that integrates cleanly into your existing spatial computing architecture.
Spatial applications often process massive WebGL renders and require extensive loading sequences before users can enter a virtual environment. Heavy client side payloads completely ruin performance metrics when immediate visual feedback is needed during these long loading phases. This component solves that bottleneck directly. By strictly avoiding external libraries like Tailwind, Bootstrap, or GSAP, it keeps your bundle size minimal. This ensures rapid rendering for XR engineers and interactive designers who need to keep users engaged on varied network connections.
Technical Architecture & Performance
-
Zero dependency codebase: Built strictly with pure HTML, CSS, and Vanilla JavaScript to keep your front end stack incredibly light.
-
Guaranteed performance metrics: Optimized to help your spatial software maintain 90 plus PageSpeed scores and pass Core Web Vitals easily.
-
Safely scoped CSS: All styling is strictly scoped to prevent any class name collisions when you drop these cards into a massive monolithic repository.
-
Sterile DOM markup: Features clean HTML with absolutely no unnecessary wrappers or deep nesting trees to parse.
Design & Aesthetic Impact
The visual direction pairs professional Ash and Charcoal tones to establish a neutral and focused background before a colorful virtual world loads. This clean and highly readable aesthetic ensures visual clarity for users waiting for complex spatial assets and dense polygon geometries to compile. For the interaction layer, we implemented custom zoom in and out loop animations. These rhythmic spatial transitions provide clear visual feedback that the environment is actively rendering without requiring heavy javascript animation scripts. The final result is a polished user interface that looks premium and functions perfectly for strict enterprise VR and AR platforms.
Enterprise Use Cases
-
WebXR portal lobbies: Display active rendering progress and spatial asset staging using the card grid so users understand their wait times before entering a virtual room.
-
Augmented reality product configurators: Build a fast rendering loading page where 3D artists can organize and present complex product models within a lightweight interface.
-
Industrial VR training hubs: Create a responsive control layout for simulation directors to track active module downloads and environment staging across multiple employee headsets.
Highlights & Benefits
Drop the code straight into your project without configuration.
Built strictly with pure CSS & Vanilla JS for maximum speed.
Constructed with strict adherence to WCAG accessibility standards for perfect contrast and screen-reader support.
Utilizes a highly optimized, clean DOM architecture ensuring lightning-fast render and maximum PageSpeed scores.

3D Environment Loader – Ash Technical
Description
Let us look at the 3D Environment Loader Ash Technical component. This free UI asset offers a modular card system specifically engineered for the virtual reality and augmented reality sector. We built this entirely from scratch to handle heavy 3D asset staging without the usual framework bloat. You get a sterile DOM structure that integrates cleanly into your existing spatial computing architecture.
Spatial applications often process massive WebGL renders and require extensive loading sequences before users can enter a virtual environment. Heavy client side payloads completely ruin performance metrics when immediate visual feedback is needed during these long loading phases. This component solves that bottleneck directly. By strictly avoiding external libraries like Tailwind, Bootstrap, or GSAP, it keeps your bundle size minimal. This ensures rapid rendering for XR engineers and interactive designers who need to keep users engaged on varied network connections.
Technical Architecture & Performance
-
Zero dependency codebase: Built strictly with pure HTML, CSS, and Vanilla JavaScript to keep your front end stack incredibly light.
-
Guaranteed performance metrics: Optimized to help your spatial software maintain 90 plus PageSpeed scores and pass Core Web Vitals easily.
-
Safely scoped CSS: All styling is strictly scoped to prevent any class name collisions when you drop these cards into a massive monolithic repository.
-
Sterile DOM markup: Features clean HTML with absolutely no unnecessary wrappers or deep nesting trees to parse.
Design & Aesthetic Impact
The visual direction pairs professional Ash and Charcoal tones to establish a neutral and focused background before a colorful virtual world loads. This clean and highly readable aesthetic ensures visual clarity for users waiting for complex spatial assets and dense polygon geometries to compile. For the interaction layer, we implemented custom zoom in and out loop animations. These rhythmic spatial transitions provide clear visual feedback that the environment is actively rendering without requiring heavy javascript animation scripts. The final result is a polished user interface that looks premium and functions perfectly for strict enterprise VR and AR platforms.
Enterprise Use Cases
-
WebXR portal lobbies: Display active rendering progress and spatial asset staging using the card grid so users understand their wait times before entering a virtual room.
-
Augmented reality product configurators: Build a fast rendering loading page where 3D artists can organize and present complex product models within a lightweight interface.
-
Industrial VR training hubs: Create a responsive control layout for simulation directors to track active module downloads and environment staging across multiple employee headsets.



