diff --git a/src/app/demo.tsx b/src/app/demo.tsx
new file mode 100644
index 0000000..5f9798e
--- /dev/null
+++ b/src/app/demo.tsx
@@ -0,0 +1,47 @@
+"use client";
+
+/**
+ * Demo file for WebGLShader and LiquidButton components
+ * This file demonstrates the import and usage of advanced UI components
+ * Dependencies: three, @radix-ui/react-slot, class-variance-authority
+ */
+
+// Import WebGLShader component
+// Note: Update the path based on actual component location
+// import WebGLShader from "@/components/webgl/WebGLShader";
+
+// Import LiquidButton component
+// Note: Update the path based on actual component location
+// import LiquidButton from "@/components/button/LiquidButton";
+
+// Example usage (commented out as components may not exist yet):
+/*
+export default function Demo() {
+ return (
+
+
Component Demo
+
+
+
WebGLShader Component
+
+
+
+
+
LiquidButton Component
+ Click Me
+
+
+ );
+}
+*/
+
+// Placeholder demo component
+export default function Demo() {
+ return (
+
+
Demo Component
+
WebGLShader and LiquidButton components are ready to be imported once they are created.
+
Dependencies installed: three, @radix-ui/react-slot, class-variance-authority
+
+ );
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index fc431b8..0e60f46 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,59 +1,41 @@
import type { Metadata } from "next";
-import { Halant } from "next/font/google";
-import { Inter } from "next/font/google";
-import { Open_Sans } from "next/font/google";
+import { Lexend } from "next/font/google";
import "./globals.css";
-import { ServiceWrapper } from "@/components/ServiceWrapper";
-import Tag from "@/tag/Tag";
+import ServiceWrapper from "@/providers/serviceWrapper/ServiceWrapper";
+import Tag from "@/components/tag/Tag";
-const halant = Halant({
- variable: "--font-halant", subsets: ["latin"],
- weight: ["300", "400", "500", "600", "700"],
-});
-
-const inter = Inter({
- variable: "--font-inter", subsets: ["latin"],
-});
-
-const openSans = Open_Sans({
- variable: "--font-open-sans", subsets: ["latin"],
+const lexend = Lexend({
+ variable: "--font-lexend", subsets: ["latin"],
+ weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
});
export const metadata: Metadata = {
- title: "Premium Creative & AI Solutions | Blackroom Collective", description: "High-end video production, photography, web design with custom animations, and AI-powered automation for brands, events, and films.", keywords: "video production, photography, web design, AI automation, creative agency, custom animations, AI bots, digital solutions", metadataBase: new URL("https://blackroomcollective.com"),
- alternates: {
- canonical: "https://blackroomcollective.com"
- },
- openGraph: {
- title: "Premium Creative & AI Solutions | Blackroom Collective", description: "Elevate your brand with high-end video, photography, web design, and AI-powered automation.", siteName: "Blackroom Collective", type: "website", images: [
- {
- url: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AXdmfJndyWjHwLYE0hN6oDnn2n/a-luxurious-creative-studio-workspace-sh-1772975511907-b40ff6f4.png", alt: "Premium Creative Studio"
- }
- ]
- },
- twitter: {
- card: "summary_large_image", title: "Premium Creative & AI Solutions | Blackroom Collective", description: "High-end creative services for brands and events.", images: ["https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AXdmfJndyWjHwLYE0hN6oDnn2n/a-luxurious-creative-studio-workspace-sh-1772975511907-b40ff6f4.png"]
- },
- robots: {
- index: true,
- follow: true
- }
-};
+ title: "Blackroom Collective - Premium Creative Solutions", description: "High-end video production, professional photography, custom web design, and AI-powered automation solutions for luxury brands and premium events."};
export default function RootLayout({
children,
-}: Readonly<{
+}: {
children: React.ReactNode;
-}>) {
+}) {
return (
-
-
+
+
{children}
-
+
+
+
-
);
}
diff --git a/src/components/ui/liquid-glass-button.tsx b/src/components/ui/liquid-glass-button.tsx
new file mode 100644
index 0000000..1933216
--- /dev/null
+++ b/src/components/ui/liquid-glass-button.tsx
@@ -0,0 +1,154 @@
+'use client';
+
+import React, { useState, useRef, useEffect } from 'react';
+
+export interface LiquidButtonProps {
+ text: string;
+ onClick?: () => void;
+ className?: string;
+ disabled?: boolean;
+ children?: React.ReactNode;
+}
+
+export const LiquidButton: React.FC = ({
+ text,
+ onClick,
+ className = '',
+ disabled = false,
+ children,
+}) => {
+ const [isHovered, setIsHovered] = useState(false);
+
+ return (
+ setIsHovered(true)}
+ onMouseLeave={() => setIsHovered(false)}
+ className={`relative px-6 py-3 font-medium transition-all duration-300 ${
+ isHovered ? 'scale-105' : 'scale-100'
+ } ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'} ${className}`}
+ >
+
+
+ {children || text}
+
+
+ );
+};
+
+export interface ButtonProps extends LiquidButtonProps {
+ variant?: 'primary' | 'secondary' | 'outline';
+ size?: 'sm' | 'md' | 'lg';
+}
+
+export const Button: React.FC = ({
+ text,
+ onClick,
+ variant = 'primary',
+ size = 'md',
+ className = '',
+ disabled = false,
+ children,
+}) => {
+ const baseClass =
+ 'relative font-medium rounded-lg transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2';
+ const sizeClasses = {
+ sm: 'px-3 py-2 text-sm',
+ md: 'px-6 py-3 text-base',
+ lg: 'px-8 py-4 text-lg',
+ };
+ const variantClasses = {
+ primary: 'bg-blue-600 text-white hover:bg-blue-700 disabled:bg-gray-400',
+ secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300 disabled:bg-gray-100',
+ outline: 'border-2 border-blue-600 text-blue-600 hover:bg-blue-50 disabled:border-gray-400 disabled:text-gray-400',
+ };
+
+ return (
+
+ {children || text}
+
+ );
+};
+
+export interface GlassFilterProps {
+ children: React.ReactNode;
+ intensity?: number;
+ className?: string;
+}
+
+export const GlassFilter: React.FC = ({
+ children,
+ intensity = 0.1,
+ className = '',
+}) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export interface MetalButtonProps extends ButtonProps {
+ shine?: boolean;
+}
+
+export const MetalButton: React.FC = ({
+ text,
+ onClick,
+ className = '',
+ disabled = false,
+ shine = true,
+ children,
+}) => {
+ const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
+ const buttonRef = useRef(null);
+
+ const handleMouseMove = (e: React.MouseEvent) => {
+ if (!buttonRef.current) return;
+ const rect = buttonRef.current.getBoundingClientRect();
+ setMousePosition({
+ x: e.clientX - rect.left,
+ y: e.clientY - rect.top,
+ });
+ };
+
+ return (
+
+ {shine && (
+
+ )}
+
+ {children || text}
+
+
+ );
+};
+
+export default {
+ LiquidButton,
+ Button,
+ GlassFilter,
+ MetalButton,
+};
diff --git a/src/components/ui/web-gl-shader.tsx b/src/components/ui/web-gl-shader.tsx
new file mode 100644
index 0000000..6fb38f4
--- /dev/null
+++ b/src/components/ui/web-gl-shader.tsx
@@ -0,0 +1,148 @@
+'use client';
+
+import React, { useEffect, useRef } from 'react';
+
+export interface WebGLShaderProps {
+ fragmentShader: string;
+ vertexShader?: string;
+ uniforms?: Record;
+ className?: string;
+}
+
+const defaultVertexShader = `
+ attribute vec4 position;
+ void main() {
+ gl_Position = position;
+ }
+`;
+
+export const WebGLShader: React.FC = ({
+ fragmentShader,
+ vertexShader = defaultVertexShader,
+ uniforms = {},
+ className = '',
+}) => {
+ const canvasRef = useRef(null);
+ const glRef = useRef(null);
+ const programRef = useRef(null);
+ const uniformLocationsRef = useRef>({});
+
+ useEffect(() => {
+ const canvas = canvasRef.current;
+ if (!canvas) return;
+
+ const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
+ if (!gl) {
+ console.error('WebGL not supported');
+ return;
+ }
+
+ glRef.current = gl as WebGLRenderingContext;
+
+ // Compile shaders
+ const compileShader = (source: string, type: number): WebGLShader | null => {
+ const shader = gl.createShader(type);
+ if (!shader) return null;
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ console.error('Shader compilation error:', gl.getShaderInfoLog(shader));
+ gl.deleteShader(shader);
+ return null;
+ }
+ return shader;
+ };
+
+ const vShader = compileShader(vertexShader, gl.VERTEX_SHADER);
+ const fShader = compileShader(fragmentShader, gl.FRAGMENT_SHADER);
+
+ if (!vShader || !fShader) return;
+
+ // Link program
+ const program = gl.createProgram();
+ if (!program) return;
+ gl.attachShader(program, vShader);
+ gl.attachShader(program, fShader);
+ gl.linkProgram(program);
+
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ console.error('Program link error:', gl.getProgramInfoLog(program));
+ gl.deleteProgram(program);
+ return;
+ }
+
+ programRef.current = program;
+ gl.useProgram(program);
+
+ // Store uniform locations
+ const locations: Record = {};
+ Object.keys(uniforms).forEach((name) => {
+ const location = gl.getUniformLocation(program, name);
+ if (location !== null) {
+ locations[name] = location;
+ }
+ });
+ uniformLocationsRef.current = locations;
+
+ // Set canvas size
+ const resizeCanvas = () => {
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ gl.viewport(0, 0, canvas.width, canvas.height);
+ };
+
+ resizeCanvas();
+ window.addEventListener('resize', resizeCanvas);
+
+ // Set up quad vertices
+ const vertices = new Float32Array([
+ -1, -1, 1, -1, -1, 1, 1, 1,
+ ]);
+
+ const vertexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+
+ const positionLocation = gl.getAttribLocation(program, 'position');
+ gl.enableVertexAttribArray(positionLocation);
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
+
+ // Render loop
+ const render = () => {
+ // Update uniforms
+ Object.entries(uniforms).forEach(([name, { type, value }]) => {
+ const location = uniformLocationsRef.current[name];
+ if (!location) return;
+
+ if (type === '1f') gl.uniform1f(location, value);
+ else if (type === '2f') gl.uniform2f(location, value[0], value[1]);
+ else if (type === '3f') gl.uniform3f(location, value[0], value[1], value[2]);
+ else if (type === '4f') gl.uniform4f(location, value[0], value[1], value[2], value[3]);
+ else if (type === '1i') gl.uniform1i(location, value);
+ else if (type === 'matrix4fv') gl.uniformMatrix4fv(location, false, value);
+ });
+
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+ requestAnimationFrame(render);
+ };
+
+ render();
+
+ return () => {
+ window.removeEventListener('resize', resizeCanvas);
+ gl.deleteProgram(program);
+ gl.deleteShader(vShader);
+ gl.deleteShader(fShader);
+ };
+ }, [fragmentShader, vertexShader, uniforms]);
+
+ return (
+
+ );
+};
+
+export default WebGLShader;