From e162d1138fba12591c2720356701d0294a505984 Mon Sep 17 00:00:00 2001 From: reng Date: Mon, 1 Sep 2025 18:46:04 +0800 Subject: [PATCH] update --- package-lock.json | 7 ++ package.json | 1 + public/cuelist.json | 27 ++++--- src-tauri/tauri.conf.json | 2 +- src/App.css | 6 +- src/App.jsx | 152 +++++++++++++++++++++++++++----------- src/utils/constant.js | 3 + src/utils/light.jsx | 103 ++++++++++++++++++++++++++ 8 files changed, 243 insertions(+), 58 deletions(-) create mode 100644 src/utils/light.jsx diff --git a/package-lock.json b/package-lock.json index 44b582c..5fe8cba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@tauri-apps/api": "^2", "@tauri-apps/plugin-log": "^2.6.0", "@tauri-apps/plugin-opener": "^2", + "gsap": "^3.13.0", "howler": "^2.2.4", "react": "^19.1.0", "react-dom": "^19.1.0", @@ -1853,6 +1854,12 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, + "node_modules/gsap": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.13.0.tgz", + "integrity": "sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw==", + "license": "Standard 'no charge' license: https://gsap.com/standard-license." + }, "node_modules/howler": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz", diff --git a/package.json b/package.json index 299609c..075ebec 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@tauri-apps/api": "^2", "@tauri-apps/plugin-log": "^2.6.0", "@tauri-apps/plugin-opener": "^2", + "gsap": "^3.13.0", "howler": "^2.2.4", "react": "^19.1.0", "react-dom": "^19.1.0", diff --git a/public/cuelist.json b/public/cuelist.json index 22fe148..061f2c2 100644 --- a/public/cuelist.json +++ b/public/cuelist.json @@ -13,30 +13,33 @@ "name": "Q2", "type": "announce", "description": "announce", - "audioCue": "Q2", - "status":"reset" - + "audioCue": "Q2" }, { "id": 3, "name": "Q3", "type": "bg", - "description": "during bg", + "description": "(START) CQ2-CQ4.1", "audioCue": "Q3", - "clientCue":"Q2" + "clientCue":"Q2", + "duration":563, + "auto": true }, { - "id": 3.1, - "name": "Q3.1", + "id": 4, + "name": "Q4", "type": "light", - "description": "fade out light", - "lightCue": "fade_out_light" + "description": "(AI) CQ4.11-CQ5.6", + "lightCue":"fade_out_light", + "duration":253, + "clientCue":"Q4.11", + "auto": true }, { - "id": 4, - "name": "Q4", + "id": 5, + "name": "Q5", "type": "bg", - "description": "Ending", + "description": "(END)", "audioCue": "Q6", "status":"end", "lightCue":"fade_in_light", diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index c33272a..990c4ef 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -13,7 +13,7 @@ "windows": [ { "title": "control-panel", - "width": 800, + "width": 1200, "height": 600 } ], diff --git a/src/App.css b/src/App.css index 8d69c33..45f4ab9 100644 --- a/src/App.css +++ b/src/App.css @@ -5,12 +5,14 @@ html{ } button{ - @apply cursor-pointer min-w-[5rem] rounded-full bg-yellow-200 p-2 text-black font-bold; + @apply cursor-pointer min-w-[3rem] rounded-full bg-yellow-200 p-2 text-black font-bold; } tr{ @apply border-b border-gray-400; } - +td{ + @apply p-1; +} input[type='range'] { overflow: hidden; /* width: 80px; */ diff --git a/src/App.jsx b/src/App.jsx index 485059c..6b79d43 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -4,6 +4,7 @@ import { invoke } from "@tauri-apps/api/core"; import { listen } from '@tauri-apps/api/event'; import "./App.css"; import { OSC_ADDRESS } from "./utils/constant"; +import { Light } from "./utils/light"; const DefaultFadeDuration = 3; // 1 second @@ -29,7 +30,10 @@ function App() { const [clientStatus, setClientStatus] = useState({}); const refCue = useRef(null); - const refNextCue = useRef(null); + // const refNextCue = useRef(null); + const refLight= useRef(); + const refDuration= useRef(); + const refTimer= useRef(); function sendOsc(addr, message, id){ @@ -57,32 +61,42 @@ function App() { function onOsc(message){ + const addr= message.addr; const [id, status, name]= message.args[0]?.split('#'); - if(clientStatus[id]){ - setClientStatus(prev=>({ - ...prev, - [id]:[ - { - status, - name, - timestamp: new Date().toLocaleTimeString(), - }, - ...prev[id], - ] - })); - }else{ - setClientStatus(prev=>({ - ...prev, - [id]:[{ - status, - name, - timestamp: new Date().toLocaleTimeString(), - }] - })); - } - - + switch(addr){ + case OSC_ADDRESS.CLIENT_STATUS: + + setClientStatus(prev=>({ + ...prev, + [id]:{ + status, + name, + timestamp: new Date().toLocaleTimeString(), + } + })); + break; + case OSC_ADDRESS.CLIENT_DURATION: + setClientStatus(prev=>({ + ...prev, + [id]:{ + ...prev[id], + duration: status, + timestamp: new Date().toLocaleTimeString(), + } + })); + break; + case OSC_ADDRESS.CLIENT_INPUT: + setClientStatus(prev=>({ + ...prev, + [id]:{ + ...prev[id], + input: status, + timestamp: new Date().toLocaleTimeString(), + } + })); + break; + } } @@ -91,6 +105,7 @@ function App() { function playCue({id, name, description, type, auto, audioFile, ...props}) { console.log('Playing cue:', {id, name, description, type, auto, audioFile, ...props}); + setCurrentCue({id, name, description, type, auto, audioFile, ...props}); // Handle other cue types and properties here if(props.audioCue){ @@ -103,6 +118,31 @@ function App() { if(props.lightCue){ // sendOsc(OSC_ADDRESS.CLIENT_INPUT, props.lightCue); + + if(props.lightCue=='fade_in_light') refLight.current.fadeIn(); // Fade in light for conversation start + if(props.lightCue=='fade_out_light') refLight.current.fadeOut(); // Fade out light for conversation end + + } + + if(props.duration){ + if(refTimer.current) clearInterval(refTimer.current); + let due= props.duration; + + console.log('Start timer:', due); + const next=cuelist.find(c=>c.id==id+1); + + refTimer.current= setInterval(()=>{ + due--; + if(due<=0){ + clearInterval(refTimer.current); + refTimer.current=null; + if(auto){ + console.log('Auto play next cue:', next); + playCue(next); + } + } + refDuration.current.innerText= secondToTime(due); + },1000); } } @@ -112,6 +152,14 @@ function App() { sendOsc(OSC_ADDRESS.STOPCUE,'','all'); sendOscToSound(OSC_ADDRESS.SCS_STOP_ALL, ''); } + function reset() { + console.log('Reset all'); + + sendOsc(OSC_ADDRESS.RESETCUE,'','all'); + sendOscToSound(OSC_ADDRESS.SCS_STOP_ALL, ''); + refLight.current.set(1); + + } function secondToTime(seconds) { const minutes = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); @@ -155,7 +203,7 @@ function App() { listen('osc_message', (event) => { - console.log(`Received OSC message: ${event.payload}`); + // console.log(`Received OSC message: ${JSON.stringify(event.payload)}`); onOsc(event.payload); }); @@ -165,14 +213,19 @@ function App() { return (
-
+
-
{currentCue ? `${currentCue.name}` : 'None'}
+
+
{currentCue ? `${currentCue.name}` : 'None'}
+
+

{timestamp}

- - + + + + { @@ -191,8 +244,10 @@ function App() { Description Type Auto - Due | Light | Audio - clientCue + Due + Light + Audio + Client @@ -214,37 +269,48 @@ function App() { {description} {EmojiType[type]} {auto ? '⤵️' : ''} - {props.duration} {props.lightCue && `L${props.lightCue}`} {props.audioCue && `S${props.audioCue}`} + {props.duration} + {props.lightCue && `L${props.lightCue}`} + {props.audioCue && `S${props.audioCue}`} {props.clientCue || ''} ))}
- +
- + - - + + + + {Array.from(Array(CLIENT_COUNT).keys()).map((i) => { const id=i+1; - const log = clientStatus[id]; + const log = clientStatus[id.toString()]; return ( - + {<> - - - + + + + + } -
id status cuetimestampcontrolinputduetimestamp
{id}{log?.length>0 &&log[0]?.status}{log?.length>0 && log[0]?.name}{log?.length>0 &&log[0]?.timestamp}{log?.status} + {log?.name} + + {log?.input?.substr(log.input.length - 20)?.split('').map((ch,i)=>i%3<1?ch:'*').join('')} + {log?.duration}{log?.timestamp} + + {cuelist?.filter(c=>c.clientCue).map(c=>( + + + + {/* */} + + ) +}); \ No newline at end of file