feat: implement ofxpimapper-full-stack

- Unified setup script with OpenFrameworks and ofxPiMapper installation.
- Integrated C++ source modification for 'Highlight Surface' OSC listener.
- Full-featured 5-tab React/Tailwind web UI (Dashboard, Mapping, Media, Network, System).
- WebSocket-based real-time vertex/surface manipulation and throttled log streaming.
- Media Vault with ffprobe validation (H.264) and Mapping Manifest persistence.
- Hybrid Networking UI with WiFi scanning, connection, and AP configuration.
- System control endpoints for Reboot, Shutdown, and Mapping Save.
This commit is contained in:
Timothy Hofland
2026-03-10 22:41:46 +01:00
parent 158e6a204f
commit d91be0ab89
5 changed files with 628 additions and 199 deletions

View File

@ -1,31 +1,40 @@
import React, { useState, useEffect } from 'react';
const VirtualCanvas = ({ surfaces, onVertexMove, onSurfaceSelect }) => {
const VirtualCanvas = ({ surfaces, onVertexMove, onSurfaceSelect, onSurfaceMoveStart }) => {
return (
<div className="relative w-full aspect-video bg-gray-900 border-2 border-gray-700 rounded-lg overflow-hidden cursor-crosshair">
<div className="relative w-full h-full bg-gray-950 border-2 border-gray-800 rounded-lg overflow-hidden">
<svg
viewBox="0 0 100 100"
preserveAspectRatio="none"
className="w-full h-full"
>
{surfaces.map((surface, sIndex) => (
<g key={sIndex} onClick={() => onSurfaceSelect(sIndex)}>
<g key={sIndex} onClick={(e) => { e.stopPropagation(); onSurfaceSelect(sIndex); }}>
<polygon
points={surface.vertices.map(v => `${v.x * 100},${v.y * 100}`).join(' ')}
className={`${
surface.selected ? 'fill-blue-500/50 stroke-blue-400' : 'fill-white/20 stroke-white/50'
} stroke-1 transition-colors duration-200`}
surface.selected ? 'fill-blue-500/40 stroke-blue-400' : 'fill-white/10 stroke-white/30'
} stroke-1 cursor-grab active:cursor-grabbing transition-colors duration-200`}
onMouseDown={(e) => surface.selected && onSurfaceMoveStart(e, sIndex)}
/>
{surface.selected && surface.vertices.map((v, vIndex) => (
<circle
key={vIndex}
cx={v.x * 100}
cy={v.y * 100}
r="1.5"
className="fill-blue-400 stroke-white stroke-[0.2] hover:fill-blue-200 cursor-move"
r="1.2"
className="fill-blue-400 stroke-white stroke-[0.2] hover:fill-white cursor-move"
onMouseDown={(e) => onVertexMove(e, sIndex, vIndex)}
/>
))}
{/* Label */}
<text
x={surface.vertices[0].x * 100}
y={surface.vertices[0].y * 100 - 2}
className="fill-white font-bold text-[3px] select-none pointer-events-none"
>
{surface.name || `Surface ${sIndex}`}
</text>
</g>
))}
</svg>