ianalin123 commited on
Commit
8cc1585
·
1 Parent(s): d091b77

refactor(app): update App and StepFeed for new fold/metrics schema

Browse files

App: default target half_horizontal→half_fold, remove foldRenderMode toggle
and state, remove targetFold/episode.target (no FOLD ghost overlay), update
props to RewardPanel (reward→metrics) and InfoBadges (info→metrics+paperState).

StepFeed: track compactness delta instead of reward.total, derive fold badge
from fold.type (valley/mountain/pleat), display fold type+angle as label,
show strain+validity inline instead of progress/economy.

Files changed (2) hide show
  1. src/App.js +12 -28
  2. src/components/StepFeed.js +34 -13
src/App.js CHANGED
@@ -12,11 +12,10 @@ const API_BASE = '';
12
 
13
  function App() {
14
  const [targets, setTargets] = useState({});
15
- const [selectedTarget, setSelectedTarget] = useState('half_horizontal');
16
  const [episode, setEpisode] = useState(null);
17
  const [currentStep, setCurrentStep] = useState(0);
18
  const [playing, setPlaying] = useState(false);
19
- const [foldRenderMode, setFoldRenderMode] = useState('progressive'); // 'progressive' | 'final'
20
  const [apiStatus, setApiStatus] = useState('connecting'); // 'connecting' | 'ok' | 'err'
21
  const [episodeLoading, setEpisodeLoading] = useState(false);
22
  const intervalRef = useRef(null);
@@ -99,7 +98,6 @@ function App() {
99
  };
100
 
101
  const targetDef = targets[selectedTarget] || null;
102
- const targetFold = episode ? episode.target : null;
103
 
104
  return (
105
  <div className="app">
@@ -138,12 +136,12 @@ function App() {
138
  <div className="canvas-row">
139
  <div className="canvas-wrap">
140
  <span className="canvas-label">
141
- TARGET — {targetDef ? targetDef.name.replace(/_/g, ' ').toUpperCase() : '—'}
142
  </span>
143
  <CreaseCanvas
144
  paperState={null}
145
- target={targetFold}
146
- label="TARGET"
147
  dim={280}
148
  ghostOnly={true}
149
  />
@@ -154,7 +152,7 @@ function App() {
154
  </span>
155
  <CreaseCanvas
156
  paperState={activeStepData ? activeStepData.paper_state : null}
157
- target={targetFold}
158
  label={currentStep === 0 ? 'INITIAL' : `STEP ${currentStep}`}
159
  dim={280}
160
  ghostOnly={false}
@@ -163,28 +161,10 @@ function App() {
163
  <div className="canvas-wrap">
164
  <div className="canvas-label-row">
165
  <span className="canvas-label">3D FOLD PREVIEW</span>
166
- <div className="fold-mode-toggle">
167
- <button
168
- className={`fold-mode-btn${foldRenderMode === 'progressive' ? ' active' : ''}`}
169
- onClick={() => setFoldRenderMode('progressive')}
170
- type="button"
171
- >
172
- PER CREASE
173
- </button>
174
- <button
175
- className={`fold-mode-btn${foldRenderMode === 'final' ? ' active' : ''}`}
176
- onClick={() => setFoldRenderMode('final')}
177
- type="button"
178
- >
179
- FOLD AT END
180
- </button>
181
- </div>
182
  </div>
183
  <Fold3DCanvas
184
  steps={episode ? episode.steps : []}
185
  currentStep={currentStep}
186
- totalSteps={totalSteps}
187
- mode={foldRenderMode}
188
  dim={280}
189
  />
190
  </div>
@@ -207,10 +187,14 @@ function App() {
207
  </div>
208
 
209
  <div className="app-right">
210
- <div className="section-header">REWARD DECOMPOSITION</div>
211
- <RewardPanel reward={activeStepData ? activeStepData.reward : null} />
212
  <div className="section-header">EPISODE INFO</div>
213
- <InfoBadges info={activeStepData ? activeStepData.info : null} targetDef={targetDef} />
 
 
 
 
214
  </div>
215
  </div>
216
  </div>
 
12
 
13
  function App() {
14
  const [targets, setTargets] = useState({});
15
+ const [selectedTarget, setSelectedTarget] = useState('half_fold');
16
  const [episode, setEpisode] = useState(null);
17
  const [currentStep, setCurrentStep] = useState(0);
18
  const [playing, setPlaying] = useState(false);
 
19
  const [apiStatus, setApiStatus] = useState('connecting'); // 'connecting' | 'ok' | 'err'
20
  const [episodeLoading, setEpisodeLoading] = useState(false);
21
  const intervalRef = useRef(null);
 
98
  };
99
 
100
  const targetDef = targets[selectedTarget] || null;
 
101
 
102
  return (
103
  <div className="app">
 
136
  <div className="canvas-row">
137
  <div className="canvas-wrap">
138
  <span className="canvas-label">
139
+ TASK — {targetDef ? targetDef.name.replace(/_/g, ' ').toUpperCase() : '—'}
140
  </span>
141
  <CreaseCanvas
142
  paperState={null}
143
+ target={null}
144
+ label="TASK"
145
  dim={280}
146
  ghostOnly={true}
147
  />
 
152
  </span>
153
  <CreaseCanvas
154
  paperState={activeStepData ? activeStepData.paper_state : null}
155
+ target={null}
156
  label={currentStep === 0 ? 'INITIAL' : `STEP ${currentStep}`}
157
  dim={280}
158
  ghostOnly={false}
 
161
  <div className="canvas-wrap">
162
  <div className="canvas-label-row">
163
  <span className="canvas-label">3D FOLD PREVIEW</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  </div>
165
  <Fold3DCanvas
166
  steps={episode ? episode.steps : []}
167
  currentStep={currentStep}
 
 
168
  dim={280}
169
  />
170
  </div>
 
187
  </div>
188
 
189
  <div className="app-right">
190
+ <div className="section-header">METRICS</div>
191
+ <RewardPanel metrics={activeStepData ? activeStepData.metrics : null} />
192
  <div className="section-header">EPISODE INFO</div>
193
+ <InfoBadges
194
+ metrics={activeStepData ? activeStepData.metrics : null}
195
+ paperState={activeStepData ? activeStepData.paper_state : null}
196
+ targetDef={targetDef}
197
+ />
198
  </div>
199
  </div>
200
  </div>
src/components/StepFeed.js CHANGED
@@ -1,14 +1,32 @@
1
  import { useEffect, useRef } from 'react';
2
 
3
- function rewardDelta(step, prevStep) {
4
- if (!step || !step.reward) return null;
5
- const curr = step.reward.total;
6
- if (prevStep && prevStep.reward) {
7
- return curr - prevStep.reward.total;
 
8
  }
9
  return curr;
10
  }
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  export default function StepFeed({ steps, currentStep }) {
13
  const feedRef = useRef(null);
14
  const activeRef = useRef(null);
@@ -34,9 +52,10 @@ export default function StepFeed({ steps, currentStep }) {
34
  {steps.map((step, idx) => {
35
  const stepNum = idx + 1;
36
  const isActive = currentStep === stepNum;
37
- const delta = rewardDelta(step, idx > 0 ? steps[idx - 1] : null);
38
- const asgn = step.fold ? step.fold.assignment : null;
39
- const instruction = step.fold ? step.fold.instruction : (step.prompt || '');
 
40
 
41
  return (
42
  <div
@@ -46,21 +65,23 @@ export default function StepFeed({ steps, currentStep }) {
46
  >
47
  <div className="step-entry-top">
48
  <span className="step-num">#{stepNum}</span>
49
- <span className="step-instruction">{instruction}</span>
50
  {asgn && (
51
  <span className={`assign-badge ${asgn}`}>{asgn}</span>
52
  )}
53
  </div>
54
  {delta !== null && (
55
  <div className="step-reward-delta">
56
- {'\u0394'} total:{' '}
57
  <span className={delta >= 0 ? 'delta-positive' : 'delta-negative'}>
58
  {delta >= 0 ? '+' : ''}{delta.toFixed(3)}
59
  </span>
60
- {step.reward && (
61
  <span style={{ color: 'var(--text-dim)' }}>
62
- {' '}| progress: {step.reward.progress.toFixed(2)}
63
- {' '}| economy: {step.reward.economy.toFixed(2)}
 
 
64
  </span>
65
  )}
66
  </div>
 
1
  import { useEffect, useRef } from 'react';
2
 
3
+ function compactnessDelta(step, prevStep) {
4
+ if (!step || !step.metrics) return null;
5
+ const curr = step.metrics.compactness;
6
+ if (curr == null) return null;
7
+ if (prevStep && prevStep.metrics && prevStep.metrics.compactness != null) {
8
+ return curr - prevStep.metrics.compactness;
9
  }
10
  return curr;
11
  }
12
 
13
+ function foldAssignment(fold) {
14
+ if (!fold) return null;
15
+ const t = fold.type || '';
16
+ if (t === 'valley') return 'V';
17
+ if (t === 'mountain') return 'M';
18
+ if (t === 'pleat') return 'P';
19
+ if (t === 'crimp') return 'C';
20
+ return t.charAt(0).toUpperCase() || null;
21
+ }
22
+
23
+ function foldLabel(fold) {
24
+ if (!fold) return '';
25
+ const type = fold.type || 'fold';
26
+ const angle = fold.angle != null ? ` ${fold.angle}°` : '';
27
+ return `${type.toUpperCase()} FOLD${angle}`;
28
+ }
29
+
30
  export default function StepFeed({ steps, currentStep }) {
31
  const feedRef = useRef(null);
32
  const activeRef = useRef(null);
 
52
  {steps.map((step, idx) => {
53
  const stepNum = idx + 1;
54
  const isActive = currentStep === stepNum;
55
+ const delta = compactnessDelta(step, idx > 0 ? steps[idx - 1] : null);
56
+ const asgn = foldAssignment(step.fold);
57
+ const label = foldLabel(step.fold);
58
+ const m = step.metrics || {};
59
 
60
  return (
61
  <div
 
65
  >
66
  <div className="step-entry-top">
67
  <span className="step-num">#{stepNum}</span>
68
+ <span className="step-instruction">{label}</span>
69
  {asgn && (
70
  <span className={`assign-badge ${asgn}`}>{asgn}</span>
71
  )}
72
  </div>
73
  {delta !== null && (
74
  <div className="step-reward-delta">
75
+ {'\u0394'} compact:{' '}
76
  <span className={delta >= 0 ? 'delta-positive' : 'delta-negative'}>
77
  {delta >= 0 ? '+' : ''}{delta.toFixed(3)}
78
  </span>
79
+ {m.max_strain != null && (
80
  <span style={{ color: 'var(--text-dim)' }}>
81
+ {' '}| strain: {m.max_strain.toFixed(4)}
82
+ {m.is_valid != null && (
83
+ <span> | {m.is_valid ? '✓' : '✗'}</span>
84
+ )}
85
  </span>
86
  )}
87
  </div>