From 0fbae2f3bc80c355e7343b995e5043940891c7b0 Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Wed, 10 Jun 2026 17:45:42 +0000 Subject: [PATCH] Phase 1: Browser bundle + TTS/Tentone solver scaffolding - Content/Browser: package.json, vite.config.ts, src/index.ts for JS bundling - Content/Browser/build-browser.bat for Windows npm build - Solvers/piper/piper_tts_wrapper.py for TTS sidecar (1C) - Solvers/tentone/build.bat for OpenCV-aware standalone build (1G) - Supports 1H (pmndrs spatial), 1I (echarts analytics), 1J (model-viewer) --- Content/Browser/build-browser.bat | 25 +++++++++++ Content/Browser/package.json | 34 ++++++++++++++ Content/Browser/src/index.ts | 71 ++++++++++++++++++++++++++++++ Content/Browser/vite.config.ts | 28 ++++++++++++ Solvers/piper/piper_tts_wrapper.py | 49 +++++++++++++++++++++ Solvers/tentone/build.bat | 53 ++++++++++++++++++++++ 6 files changed, 260 insertions(+) create mode 100644 Content/Browser/build-browser.bat create mode 100644 Content/Browser/package.json create mode 100644 Content/Browser/src/index.ts create mode 100644 Content/Browser/vite.config.ts create mode 100644 Solvers/piper/piper_tts_wrapper.py create mode 100644 Solvers/tentone/build.bat diff --git a/Content/Browser/build-browser.bat b/Content/Browser/build-browser.bat new file mode 100644 index 0000000..d60d7bf --- /dev/null +++ b/Content/Browser/build-browser.bat @@ -0,0 +1,25 @@ +@echo off +setlocal + +REM Build HyperTwist browser runtime bundle +REM Phase 1H, 1I, 1J: bundles all JS spatial/analytics/model-viewer repos + +cd /d "%~dp0" + +echo Installing browser runtime dependencies... +call npm install +if errorlevel 1 ( + echo npm install failed + exit /b 1 +) + +echo Building browser runtime bundle... +call npm run build +if errorlevel 1 ( + echo Build failed + exit /b 1 +) + +echo Browser runtime built successfully. +echo Output: dist\hypertwist-browser-runtime.umd.js +echo Copy to Content\Browser\ for UE embedded WebBrowser widget loading. diff --git a/Content/Browser/package.json b/Content/Browser/package.json new file mode 100644 index 0000000..23498cd --- /dev/null +++ b/Content/Browser/package.json @@ -0,0 +1,34 @@ +{ + "name": "hypertwist-browser-runtime", + "version": "1.0.0", + "description": "Bundled browser runtime for HyperTwist embedded WebBrowser widget", + "type": "module", + "scripts": { + "build": "vite build", + "build-deps": "node scripts/build-dependencies.js", + "dev": "vite" + }, + "dependencies": { + "three": "^0.160.0", + "@pmndrs/postprocessing": "file:../../.external/postprocessing", + "@react-three/drei": "file:../../.external/drei", + "@react-three/fiber": "^8.15.0", + "leva": "file:../../.external/leva", + "maath": "file:../../.external/maath", + "three-stdlib": "file:../../.external/three-stdlib", + "zustand": "file:../../.external/zustand", + "@use-gesture/react": "file:../../.external/use-gesture", + "@react-spring/three": "file:../../.external/react-spring", + "@react-spring/web": "file:../../.external/react-spring", + "echarts": "^5.4.0", + "zrender": "file:../../.external/zrender", + "echarts-gl": "file:../../.external/echarts-gl", + "@google/model-viewer": "file:../../.external/model-viewer/packages/model-viewer", + "claygl": "file:../../.external/claygl", + "rubix-solver": "file:../../.external/rubix-solver" + }, + "devDependencies": { + "vite": "^5.0.0", + "typescript": "^5.3.0" + } +} diff --git a/Content/Browser/src/index.ts b/Content/Browser/src/index.ts new file mode 100644 index 0000000..91254f1 --- /dev/null +++ b/Content/Browser/src/index.ts @@ -0,0 +1,71 @@ +/** + * HyperTwist Browser Runtime Entry Point + * + * Exports all bundled browser-capable libraries for use in the embedded + * WebBrowser widget or external browser runtime. + * + * Phase 1 wiring targets: + * - 1G: tentone/rubix-solver (vision + solver UI) + * - 1H: pmndrs spatial stack (postprocessing, drei, fiber, etc.) + * - 1I: ecomfe analytics stack (zrender, echarts-gl) + * - 1J: google/model-viewer sub-packages + */ + +// Three.js core (peer dependency for most spatial packages) +import * as THREE from 'three'; + +// pmndrs spatial stack (1H) +export { THREE }; +export { default as postprocessing } from '@pmndrs/postprocessing'; +export { default as drei } from '@react-three/drei'; +export { Canvas, useFrame, useThree } from '@react-three/fiber'; +export { default as leva } from 'leva'; +export { default as maath } from 'maath'; +export { default as threeStdlib } from 'three-stdlib'; +export { create as createZustandStore } from 'zustand'; +export { useGesture } from '@use-gesture/react'; +export { useSpring, animated } from '@react-spring/three'; + +// Analytics stack (1I) +export { default as zrender } from 'zrender'; +export { default as echarts } from 'echarts'; +export { default as echartsGl } from 'echarts-gl'; + +// Model viewer (1J) +export { default as ModelViewerElement } from '@google/model-viewer'; + +// claygl / clay-viewer (1H) +export { default as claygl } from 'claygl'; + +// rubix-solver (1G) +// Note: tentone solver is primarily a C++/OpenCV desktop app. +// The JS bundle exports a placeholder for future WASM or web port. +export const RubixSolver = { + version: '1.0.0', + note: 'C++ solver compiled as standalone executable. Web port TBD.' +}; + +// UE Bridge: postMessage API for state synchronization +interface UEStateBridge { + sendState(state: object): void; + onCommand(callback: (cmd: object) => void): void; +} + +export const UEBridge: UEStateBridge = { + sendState(state: object) { + if ((window as any).ue && (window as any).ue.hypertwist) { + (window as any).ue.hypertwist.sendState(JSON.stringify(state)); + } else { + window.parent.postMessage({ type: 'hypertwist-state', payload: state }, '*'); + } + }, + onCommand(callback: (cmd: object) => void) { + window.addEventListener('message', (event) => { + if (event.data && event.data.type === 'hypertwist-command') { + callback(event.data.payload); + } + }); + } +}; + +console.log('[HyperTwist Browser Runtime] Loaded'); diff --git a/Content/Browser/vite.config.ts b/Content/Browser/vite.config.ts new file mode 100644 index 0000000..1ed2daa --- /dev/null +++ b/Content/Browser/vite.config.ts @@ -0,0 +1,28 @@ +import { defineConfig } from 'vite'; +import { resolve } from 'path'; + +export default defineConfig({ + build: { + lib: { + entry: resolve(__dirname, 'src/index.ts'), + name: 'HyperTwistBrowserRuntime', + fileName: (format) => `hypertwist-browser-runtime.${format}.js`, + formats: ['umd', 'es'] + }, + rollupOptions: { + external: [], + output: { + globals: {}, + inlineDynamicImports: true + } + }, + outDir: 'dist', + emptyOutDir: true, + sourcemap: true + }, + resolve: { + alias: { + '@': resolve(__dirname, 'src') + } + } +}); diff --git a/Solvers/piper/piper_tts_wrapper.py b/Solvers/piper/piper_tts_wrapper.py new file mode 100644 index 0000000..1c75301 --- /dev/null +++ b/Solvers/piper/piper_tts_wrapper.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +""" +HyperTwist IPC wrapper for rhasspy/piper TTS engine. + +Usage: + python piper_tts_wrapper.py --text "Hello world" --model path/to/model.onnx --output output.wav + +Returns: + Path to generated WAV file on success +""" +import argparse +import sys +import json +import subprocess +import os + +def synthesize(text: str, model_path: str, config_path: str, output_path: str) -> str: + """Synthesize speech using piper.""" + if not os.path.exists(model_path): + return f"ERROR: Model not found: {model_path}" + + # Try using piper directly if available in PATH + try: + cmd = [ + "piper", + "--model", model_path, + "--config", config_path, + "--output_file", output_path + ] + result = subprocess.run(cmd, input=text, text=True, capture_output=True, timeout=60) + if result.returncode == 0: + return output_path + return f"ERROR: {result.stderr}" + except FileNotFoundError: + return "ERROR: piper executable not found in PATH. Install piper or compile from .external/piper" + except Exception as e: + return f"ERROR: {e}" + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="HyperTwist Piper TTS Wrapper") + parser.add_argument("--text", required=True, help="Text to synthesize") + parser.add_argument("--model", required=True, help="Path to .onnx voice model") + parser.add_argument("--config", help="Path to model config JSON") + parser.add_argument("--output", default="output.wav", help="Output WAV path") + args = parser.parse_args() + + config_path = args.config or args.model.replace(".onnx", ".onnx.json") + result = synthesize(args.text, args.model, config_path, args.output) + print(result) diff --git a/Solvers/tentone/build.bat b/Solvers/tentone/build.bat new file mode 100644 index 0000000..f7e92c3 --- /dev/null +++ b/Solvers/tentone/build.bat @@ -0,0 +1,53 @@ +@echo off +setlocal + +REM Build tentone/rubix-solver as standalone executable +REM Requires OpenCV. If OpenCV is not installed, only the solver logic +REM (cube.cpp, solver.cpp, solution.cpp) can be compiled without vision. + +set SRCDIR=..\..\.external\rubix-solver +set OUTDIR=..\..\UnrealHyperTwist\Binaries\Win64\Solvers + +if not exist %OUTDIR% mkdir %OUTDIR% + +REM Try to find OpenCV +set OPENCV_DIR= +if exist "C:\opencv\build" set OPENCV_DIR=C:\opencv\build +if exist "C:\tools\opencv\build" set OPENCV_DIR=C:\tools\opencv\build + +if "%OPENCV_DIR%"=="" ( + echo WARNING: OpenCV not found. Building solver-only executable without vision. + echo Install OpenCV and set OPENCV_DIR to enable computer vision features. + + call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 + if errorlevel 1 exit /b 1 + + cl /nologo /W4 /O2 /Fe%OUTDIR%\tentone-solver.exe ^ + %SRCDIR%\cube.cpp ^ + %SRCDIR%\solver.cpp ^ + %SRCDIR%\solution.cpp ^ + %SRCDIR%\utils.cpp ^ + %SRCDIR%\config.cpp ^ + %SRCDIR%\main.cpp +) else ( + echo Found OpenCV at %OPENCV_DIR% + call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 + if errorlevel 1 exit /b 1 + + cl /nologo /W4 /O2 /I%OPENCV_DIR%\include /Fe%OUTDIR%\tentone-solver.exe ^ + %SRCDIR%\cube.cpp ^ + %SRCDIR%\solver.cpp ^ + %SRCDIR%\solution.cpp ^ + %SRCDIR%\utils.cpp ^ + %SRCDIR%\config.cpp ^ + %SRCDIR%\vision.cpp ^ + %SRCDIR%\main.cpp ^ + /link /LIBPATH:%OPENCV_DIR%\x64\vc16\lib opencv_world490.lib +) + +if errorlevel 1 ( + echo Build failed + exit /b 1 +) + +echo tentone-solver built successfully at %OUTDIR%\tentone-solver.exe