Skip to content

Commit d1e5d99

Browse files
committed
feat: refactor time to be in millisecond
1 parent a27f3f5 commit d1e5d99

File tree

6 files changed

+37
-38
lines changed

6 files changed

+37
-38
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ startHaptic(
7171
{
7272
type: 'continuous',
7373
relativeTime: 0,
74-
duration: 1.2,
74+
duration: 1200,
7575
parameters: [
7676
{ type: 'intensity', value: 0.2 },
7777
{ type: 'sharpness', value: 0.5 },
@@ -83,9 +83,9 @@ startHaptic(
8383
type: 'intensity',
8484
relativeTime: 0,
8585
controlPoints: [
86-
{ relativeTime: 0.0, value: 0.2 },
87-
{ relativeTime: 0.6, value: 1.0 },
88-
{ relativeTime: 1.2, value: 0.2 },
86+
{ relativeTime: 0, value: 0.2 },
87+
{ relativeTime: 600, value: 1.0 },
88+
{ relativeTime: 1200, value: 0.2 },
8989
],
9090
},
9191
]
@@ -109,8 +109,8 @@ startHaptic(
109109
},
110110
{
111111
type: 'continuous',
112-
relativeTime: 0.05,
113-
duration: 0.8,
112+
relativeTime: 50,
113+
duration: 800,
114114
parameters: [
115115
{ type: 'intensity', value: 0.2 },
116116
{ type: 'sharpness', value: 0.4 },

example/src/components/RecordingTimeline.tsx

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ const TRANSIENT_INTENSITY_COLOR = '#00E5FF';
3838
const TRANSIENT_SHARPNESS_COLOR = '#FFB366';
3939

4040
export const TIMELINE_WIDTH = SCREEN_WIDTH - 32;
41-
export const PIXELS_PER_SECOND = 100;
41+
export const PIXELS_PER_MILLISECOND = 0.1;
42+
const PIXELS_PER_SECOND = PIXELS_PER_MILLISECOND * 1000;
4243
export const PLAYHEAD_OFFSET = TIMELINE_WIDTH / 2;
4344

4445
const DOWNSAMPLE_INTERVAL_PX = 1;
@@ -61,7 +62,7 @@ const LANE_GAP = 4;
6162
const LANE_PADDING = 6;
6263

6364
const MAX_CONTENT_WIDTH =
64-
PLAYHEAD_OFFSET + 120 * PIXELS_PER_SECOND + PLAYHEAD_OFFSET;
65+
PLAYHEAD_OFFSET + 120000 * PIXELS_PER_MILLISECOND + PLAYHEAD_OFFSET; // 120 seconds in ms
6566

6667
export default function RecordingTimeline({
6768
mode,
@@ -128,7 +129,7 @@ export default function RecordingTimeline({
128129
const userScrolling = isDragging.get() || isMomentumScrolling.get();
129130
if (!userScrolling) return;
130131

131-
const maxScroll = totalDuration.get() * PIXELS_PER_SECOND;
132+
const maxScroll = totalDuration.get() * PIXELS_PER_MILLISECOND;
132133
const rawX = event.contentOffset.x;
133134
const clampedX = Math.min(Math.max(0, rawX), maxScroll);
134135

@@ -143,8 +144,8 @@ export default function RecordingTimeline({
143144
scrollX.set(clampedX);
144145

145146
// Haptic feedback at timeline marks
146-
const currentTimeSeconds = clampedX / PIXELS_PER_SECOND;
147-
const currentMark = Math.floor(currentTimeSeconds * 10); // 0.1s precision
147+
const currentTimeMs = clampedX / PIXELS_PER_MILLISECOND;
148+
const currentMark = Math.floor(currentTimeMs / 100); // 100ms precision
148149
const lastMark = lastHapticMark.get();
149150

150151
if (currentMark !== lastMark) {
@@ -158,15 +159,15 @@ export default function RecordingTimeline({
158159
}
159160
}
160161

161-
onSeek(clampedX / PIXELS_PER_SECOND);
162+
onSeek(clampedX / PIXELS_PER_MILLISECOND); // Already in milliseconds
162163
},
163164

164165
onEndDrag: (event) => {
165166
isDragging.set(false);
166167

167168
const m = mode.get();
168169
if (m === 'playback') {
169-
const maxScroll = totalDuration.get() * PIXELS_PER_SECOND;
170+
const maxScroll = totalDuration.get() * PIXELS_PER_MILLISECOND;
170171
if (event.contentOffset.x > maxScroll) {
171172
scrollX.set(maxScroll);
172173
scrollTo(scrollViewRef, maxScroll, 0, true);
@@ -191,12 +192,12 @@ export default function RecordingTimeline({
191192

192193
const m = mode.get();
193194
if (m === 'playback') {
194-
const maxScroll = totalDuration.get() * PIXELS_PER_SECOND;
195+
const maxScroll = totalDuration.get() * PIXELS_PER_MILLISECOND;
195196
const currentScroll = scrollX.get();
196197
if (currentScroll > maxScroll) {
197198
scrollX.set(maxScroll);
198199
scrollTo(scrollViewRef, maxScroll, 0, true);
199-
onSeek(totalDuration.get());
200+
onSeek(totalDuration.get()); // Already in milliseconds
200201
}
201202
}
202203

@@ -211,7 +212,7 @@ export default function RecordingTimeline({
211212
.get()
212213
.filter((e) => e.type === 'transient')
213214
.map((e) => ({
214-
x: PLAYHEAD_OFFSET + e.timestamp * PIXELS_PER_SECOND,
215+
x: PLAYHEAD_OFFSET + e.timestamp * PIXELS_PER_MILLISECOND,
215216
intensity: e.intensity,
216217
sharpness: e.sharpness,
217218
}));
@@ -224,7 +225,7 @@ export default function RecordingTimeline({
224225

225226
for (const event of events.get()) {
226227
if (event.type === 'continuous_start') {
227-
const x = PLAYHEAD_OFFSET + event.timestamp * PIXELS_PER_SECOND;
228+
const x = PLAYHEAD_OFFSET + event.timestamp * PIXELS_PER_MILLISECOND;
228229
currentSegment = {
229230
points: [
230231
{ x, intensity: event.intensity, sharpness: event.sharpness },
@@ -238,7 +239,7 @@ export default function RecordingTimeline({
238239
event.type === 'continuous_end') &&
239240
currentSegment
240241
) {
241-
const x = PLAYHEAD_OFFSET + event.timestamp * PIXELS_PER_SECOND;
242+
const x = PLAYHEAD_OFFSET + event.timestamp * PIXELS_PER_MILLISECOND;
242243
currentSegment.endX = x;
243244

244245
if (

example/src/contexts/RecorderContext.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
trimHapticDataFromSeekTime,
1717
hapticEventsToRecordingEvents,
1818
} from '../utils/hapticPlayback';
19-
import { PIXELS_PER_SECOND } from '../components/RecordingTimeline';
19+
import { PIXELS_PER_MILLISECOND } from '../components/RecordingTimeline';
2020
import { scheduleOnRN } from 'react-native-worklets';
2121
import { storage, STORAGE_KEYS } from '../utils/storage';
2222

@@ -111,21 +111,21 @@ export function RecorderProvider({ children }: { children: ReactNode }) {
111111
const now = Date.now();
112112

113113
if (mode.get() === 'recording' && isRecording.get()) {
114-
const elapsed = (now - recordingStartTimestamp.get()) / 1000;
114+
const elapsed = now - recordingStartTimestamp.get();
115115
recordingTime.set(elapsed);
116-
scrollX.set(elapsed * PIXELS_PER_SECOND);
116+
scrollX.set(elapsed * PIXELS_PER_MILLISECOND);
117117
} else if (mode.get() === 'playback' && isPlaying.get()) {
118-
const elapsed = (now - playbackStartTimestamp.get()) / 1000;
118+
const elapsed = now - playbackStartTimestamp.get();
119119
const newTime = playbackStartTime.get() + elapsed;
120120
const maxTime = playbackTotalDuration.get();
121121

122122
if (newTime >= maxTime) {
123123
playbackTime.set(maxTime);
124124
isPlaying.set(false);
125-
scrollX.set(maxTime * PIXELS_PER_SECOND);
125+
scrollX.set(maxTime * PIXELS_PER_MILLISECOND);
126126
} else {
127127
playbackTime.set(newTime);
128-
scrollX.set(newTime * PIXELS_PER_SECOND);
128+
scrollX.set(newTime * PIXELS_PER_MILLISECOND);
129129
}
130130
}
131131
}, false);
@@ -379,7 +379,7 @@ export function RecorderProvider({ children }: { children: ReactNode }) {
379379
'worklet';
380380
isUserScrolling.set(false);
381381
const time = playbackTime.get();
382-
scrollX.set(time * PIXELS_PER_SECOND);
382+
scrollX.set(time * PIXELS_PER_MILLISECOND);
383383
};
384384

385385
const deleteRecording = (id: string) => {

example/src/screens/Recorder.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ function RecorderContent() {
8080
const durationText = useDerivedValue(() => {
8181
const m = mode.get();
8282
if (m === 'recording') {
83-
return `${recordingTime.get().toFixed(1)}s`;
83+
return `${(recordingTime.get() / 1000).toFixed(1)}s`;
8484
}
8585
if (m === 'playback') {
86-
const current = playbackTime.get();
87-
const total = playbackTotalDuration.get();
86+
const current = playbackTime.get() / 1000;
87+
const total = playbackTotalDuration.get() / 1000;
8888
return `${current.toFixed(1)}s / ${total.toFixed(1)}s`;
8989
}
9090
return '';

example/src/utils/hapticPlayback.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,11 @@ export function hapticEventsToRecordingEvents(
7676
if (curves) {
7777
const intensityCurve = curves.find(
7878
(c) =>
79-
c.type === 'intensity' &&
80-
Math.abs(c.relativeTime - eventStart) < 0.001
79+
c.type === 'intensity' && Math.abs(c.relativeTime - eventStart) < 1
8180
);
8281
const sharpnessCurve = curves.find(
8382
(c) =>
84-
c.type === 'sharpness' &&
85-
Math.abs(c.relativeTime - eventStart) < 0.001
83+
c.type === 'sharpness' && Math.abs(c.relativeTime - eventStart) < 1
8684
);
8785

8886
const intensityPoints = intensityCurve?.controlPoints ?? [];
@@ -106,7 +104,7 @@ export function hapticEventsToRecordingEvents(
106104
let intensityValue = intensity;
107105
if (intensityPoints.length > 0) {
108106
const exactPoint = intensityPoints.find(
109-
(p) => Math.abs(p.relativeTime - t) < 0.001
107+
(p) => Math.abs(p.relativeTime - t) < 1
110108
);
111109
if (exactPoint) {
112110
intensityValue = exactPoint.value;
@@ -134,7 +132,7 @@ export function hapticEventsToRecordingEvents(
134132
let sharpnessValue = sharpness;
135133
if (sharpnessPoints.length > 0) {
136134
const exactPoint = sharpnessPoints.find(
137-
(p) => Math.abs(p.relativeTime - t) < 0.001
135+
(p) => Math.abs(p.relativeTime - t) < 1
138136
);
139137
if (exactPoint) {
140138
sharpnessValue = exactPoint.value;

ios/Ahap.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,20 @@ class Ahap: HybridAhapSpec {
5353
return CHHapticEvent(
5454
eventType: eventType,
5555
parameters: parameters,
56-
relativeTime: event.relativeTime,
57-
duration: event.type == .continuous ? event.duration ?? 1.0 : 0
56+
relativeTime: event.relativeTime / 1000.0,
57+
duration: event.type == .continuous ? (event.duration ?? 1000.0) / 1000.0 : 0
5858
)
5959
}
6060

6161
let hapticCurves = curves.map { curve -> CHHapticParameterCurve in
6262
let parameterID: CHHapticDynamicParameter.ID = (curve.type == .intensity) ? .hapticIntensityControl : .hapticSharpnessControl
6363
let controlPoints = curve.controlPoints.map { controlPoint -> CHHapticParameterCurve.ControlPoint in
64-
return CHHapticParameterCurve.ControlPoint(relativeTime: controlPoint.relativeTime, value: Float(controlPoint.value))
64+
return CHHapticParameterCurve.ControlPoint(relativeTime: controlPoint.relativeTime / 1000.0, value: Float(controlPoint.value))
6565
}
6666
return CHHapticParameterCurve(
6767
parameterID: parameterID,
6868
controlPoints: controlPoints,
69-
relativeTime: curve.relativeTime
69+
relativeTime: curve.relativeTime / 1000.0
7070
)
7171
}
7272

0 commit comments

Comments
 (0)