🚀 Auto-deploy: melhoria no snap e medição AR em 30/05/2026 14:52:07
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import { ShieldCheck, Ruler, Scissors, ArrowRight } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
export function LandingContent() {
|
||||
return (
|
||||
<div className="w-full max-w-4xl mx-auto space-y-12 py-12">
|
||||
{/* Hero Section */}
|
||||
<section className="text-center space-y-6 px-4">
|
||||
<h2 className="text-4xl md:text-5xl font-bold tracking-tight text-foreground">
|
||||
Controle total da qualidade em obras metálicas e civis — <br className="hidden md:block" />
|
||||
<span className="text-primary">direto no canteiro, em Realidade Aumentada.</span>
|
||||
</h2>
|
||||
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
|
||||
visualize. Meça. inspire confiança.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Benefits Section */}
|
||||
<section className="grid md:grid-cols-3 gap-6 px-4">
|
||||
<div className="rounded-xl border bg-card p-6 space-y-4 hover:border-primary/50 transition-colors">
|
||||
<div className="h-12 w-12 rounded-lg bg-primary/10 flex items-center justify-center">
|
||||
<ShieldCheck className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-foreground">
|
||||
Inspeção por Checklist Digital com Gravação de Voz
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Elimine planilhas de papel. Faça inspeções de qualidade diretamente no modelo 3D, com aprovação ou reprovação de cada item e anotações por voz — tudo rastreável e auditável.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="rounded-xl border bg-card p-6 space-y-4 hover:border-primary/50 transition-colors">
|
||||
<div className="h-12 w-12 rounded-lg bg-primary/10 flex items-center justify-center">
|
||||
<Ruler className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-foreground">
|
||||
Medições Precisas em AR com Snap Inteligente
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
O controlador XR identifica automaticamente vértices, arestas e furos nos modelos IFC. O resultado são medições em milímetros reais, sem depender de trena ou cálculos manuais.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="rounded-xl border bg-card p-6 space-y-4 hover:border-primary/50 transition-colors">
|
||||
<div className="h-12 w-12 rounded-lg bg-primary/10 flex items-center justify-center">
|
||||
<Scissors className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-foreground">
|
||||
Cortes de Seção Interativos para Análise Estrutural
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Visualize o interior de estruturas metálicas com cortes dinâmicos nos eixos X, Y e Z — sem desmontar nada. Ideal para validar projetos complexos antes da montagem.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Final CTA Section */}
|
||||
<section className="px-4 text-center space-y-6">
|
||||
<div className="rounded-2xl border border-border bg-gradient-to-b from-card to-muted/20 p-8 md:p-12">
|
||||
<p className="text-muted-foreground max-w-2xl mx-auto text-base md:text-lg leading-relaxed">
|
||||
Atrasos por erros de medição, retrabalho por falhas de comunicação e perdas por não conformidade são o pesadelo de qualquer gestão de produção metalmecânica ou obra civil. O TrackSteelXR coloca o modelo 3D IFC no canteiro — em AR — para que engenheiros e gestores tomem decisões precisas no momento certo. <span className="font-semibold text-foreground">Menos retrabalho, mais produtividade, entregas dentro do prazo.</span>
|
||||
</p>
|
||||
<div className="mt-8 flex justify-center gap-4">
|
||||
<Button size="lg" className="gap-2">
|
||||
Começar Agora
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button size="lg" variant="outline" className="gap-2">
|
||||
Ver Demonstração
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+9
-2
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef, useCallback, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Upload, Glasses, CheckCircle, XCircle, Loader2, Box, Package, Users } from 'lucide-react';
|
||||
import { Upload, Glasses, CheckCircle, XCircle, Loader2, Box, Package, Users, Info } from 'lucide-react';
|
||||
import { LandingContent } from '@/components/LandingContent';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useModelStore } from '@/stores/useModelStore';
|
||||
import { toast } from 'sonner';
|
||||
@@ -20,6 +21,7 @@ const Index = () => {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const [loadingDemoIFC, setLoadingDemoIFC] = useState(false);
|
||||
const [loadingDemoCotovelo, setLoadingDemoCotovelo] = useState(false);
|
||||
const [showLanding, setShowLanding] = useState(false);
|
||||
|
||||
const [converting, setConverting] = useState(false);
|
||||
const { model, addModel, models, maxModels, xrSupported, setXrSupported } = useModelStore();
|
||||
@@ -209,18 +211,23 @@ const Index = () => {
|
||||
|
||||
|
||||
{/* Logo area */}
|
||||
<div className="mb-12 text-center">
|
||||
<div className="mb-8 text-center">
|
||||
<div className="mb-4 flex items-center justify-center gap-3">
|
||||
<Box className="h-10 w-10 text-primary" />
|
||||
<h1 className="text-3xl font-bold tracking-tight text-foreground md:text-4xl">
|
||||
TrackSteel<span className="text-primary">XR</span>
|
||||
</h1>
|
||||
<Button variant="ghost" size="icon" className="ml-2" onClick={() => setShowLanding(!showLanding)} title="Sobre">
|
||||
<Info className="h-5 w-5" />
|
||||
</Button>
|
||||
</div>
|
||||
<p className="font-mono text-sm uppercase tracking-widest text-muted-foreground">
|
||||
Inspeção de Qualidade Industrial
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{showLanding && <LandingContent />}
|
||||
|
||||
{/* Main card */}
|
||||
<div className="w-full max-w-md space-y-4">
|
||||
{/* Import button */}
|
||||
|
||||
+16
-10
@@ -531,6 +531,7 @@ function HologramModel({ model, presentationState, isPresenter, onPresentationCh
|
||||
const { scene } = useGLTF(model.url);
|
||||
const clone = useMemo(() => scene.clone(), [scene]);
|
||||
const presentationGroupRef = useRef<THREE.Group>(null);
|
||||
const [presenterGroup, setPresenterGroup] = useState<THREE.Group | null>(null);
|
||||
const baseScaleRef = useRef<number>(1);
|
||||
const centerRef = useRef<THREE.Vector3>(new THREE.Vector3());
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
@@ -590,13 +591,14 @@ function HologramModel({ model, presentationState, isPresenter, onPresentationCh
|
||||
|
||||
// Aplica transformações de Rotação e Escala compartilhadas no grupo externo de apresentação
|
||||
useFrame(() => {
|
||||
if (presentationGroupRef.current && presentationState && !isDragging) {
|
||||
const targetGroup = presentationGroupRef.current || presenterGroup;
|
||||
if (targetGroup && presentationState && !isDragging) {
|
||||
const { rotation, scale } = presentationState;
|
||||
if (rotation) {
|
||||
presentationGroupRef.current.rotation.set(rotation[0], rotation[1], rotation[2]);
|
||||
targetGroup.rotation.set(rotation[0], rotation[1], rotation[2]);
|
||||
}
|
||||
if (scale) {
|
||||
presentationGroupRef.current.scale.setScalar(baseScaleRef.current * scale);
|
||||
targetGroup.scale.setScalar(baseScaleRef.current * scale);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -666,20 +668,20 @@ function HologramModel({ model, presentationState, isPresenter, onPresentationCh
|
||||
|
||||
return (
|
||||
<>
|
||||
{isPresenter && (
|
||||
{isPresenter && presenterGroup && (
|
||||
<TransformControls
|
||||
object={presentationGroupRef}
|
||||
object={presenterGroup}
|
||||
mode="rotate"
|
||||
size={0.6}
|
||||
onMouseDown={() => setIsDragging(true)}
|
||||
onMouseUp={() => setIsDragging(false)}
|
||||
onChange={() => {
|
||||
if (isDragging && presentationGroupRef.current) {
|
||||
if (isDragging && presenterGroup) {
|
||||
onPresentationChange({
|
||||
rotation: [
|
||||
presentationGroupRef.current.rotation.x,
|
||||
presentationGroupRef.current.rotation.y,
|
||||
presentationGroupRef.current.rotation.z
|
||||
presenterGroup.rotation.x,
|
||||
presenterGroup.rotation.y,
|
||||
presenterGroup.rotation.z
|
||||
]
|
||||
});
|
||||
}
|
||||
@@ -687,7 +689,11 @@ function HologramModel({ model, presentationState, isPresenter, onPresentationCh
|
||||
/>
|
||||
)}
|
||||
{/* Grupo Externo de Apresentação Compartilhada */}
|
||||
<group ref={presentationGroupRef}>
|
||||
<group ref={(node) => {
|
||||
// @ts-ignore
|
||||
presentationGroupRef.current = node;
|
||||
setPresenterGroup(node);
|
||||
}}>
|
||||
{/* Ignoramos fineTuning.posX/Y/Z para ancorar perfeitamente à mesa */}
|
||||
<group>
|
||||
{/* Grupo de Rotação Fina e Escala Fina */}
|
||||
|
||||
Reference in New Issue
Block a user