Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "beatmapper",
"version": "0.5.2",
"version": "0.5.3",
"type": "module",
"private": true,
"packageManager": "pnpm@11.5.2",
Expand Down Expand Up @@ -41,7 +41,7 @@
"@zag-js/file-utils": "^1.37.0",
"@zag-js/react": "^1.37.0",
"@zag-js/utils": "^1.37.0",
"bsmap": "^3.0.0",
"bsmap": "^3.1.4",
"date-fns": "^4.1.0",
"fflate": "^0.8.2",
"file-saver": "^2.0.5",
Expand Down
13 changes: 0 additions & 13 deletions patches/bsmap@3.0.0.patch

This file was deleted.

784 changes: 490 additions & 294 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,5 @@ allowBuilds:
minimumReleaseAgeExclude:
- bsmap

patchedDependencies:
bsmap@3.0.0: patches/bsmap@3.0.0.patch

publicHoistPattern:
- "*workbox*"
2 changes: 1 addition & 1 deletion src/components/app/forms/settings/advanced.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function AppAdvancedSettings() {
<Stack gap={4}>
<Wrap gap={2}>
<Field label="Event update rate" helperText="Controls how often debounced/throttled events will fire (in milliseconds). A lower value will make certain elements more responsive, with the trade-off being a greater impact on performance.">
<FieldInput type="number" value={wait} onValueChange={(x) => dispatch(updatePacerWait({ value: x.valueAsNumber }))} />
<FieldInput type="number" value={wait} onValueChange={(x) => dispatch(updatePacerWait(x.valueAsNumber))} />
</Field>
</Wrap>
</Stack>
Expand Down
3 changes: 3 additions & 0 deletions src/components/app/layouts/event-grid/machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ export function connect({ scope, send, prop, context, refs, computed }: Service<
return normalize.element({
...getProps(scope, "trigger"),
onPointerDown: (event) => {
if (!isPlaceMode) {
event.currentTarget.setPointerCapture(event.pointerId);
}
const rect = event.currentTarget.getBoundingClientRect();
return send({ type: "trigger/down", x: event.clientX - rect.left, y: event.clientY - rect.top, button: event.button });
},
Expand Down
50 changes: 20 additions & 30 deletions src/components/app/templates/editor/song-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,7 @@ import { useAppDispatch, useAppSelector } from "$/store/hooks";
import { selectBeatmaps, selectSelectedBeatmap, selectSongMetadata } from "$/store/selectors";
import { HStack, Stack, styled, Text } from "$:styled-system/jsx";

const COVER_ART_SIZES = {
medium: 75,
small: 50,
};

interface Props {
showDifficultySelector: boolean;
}
function EditorSongInfo({ showDifficultySelector }: Props) {
function EditorSongInfo() {
const { sid } = useParams({ from: "/_/edit/$sid/$bid/_" });
const { view } = useRouteContext({ from: "/_/edit/$sid/$bid/_" });

Expand All @@ -48,7 +40,7 @@ function EditorSongInfo({ showDifficultySelector }: Props) {

return (
<OuterWrapper gap={1.5}>
<CoverArtFile filename={BeatmapFilestore.resolveFilename(sid, "cover", {})} boxSize={COVER_ART_SIZES[showDifficultySelector ? "medium" : "small"]} />
<CoverArtFile filename={BeatmapFilestore.resolveFilename(sid, "cover", {})} boxSize={75} />
<Stack gap={1}>
<Stack gap={0.5}>
<Text color={"fg.default"} fontSize={"20px"} fontWeight={400} lineHeight={1}>
Expand All @@ -58,26 +50,24 @@ function EditorSongInfo({ showDifficultySelector }: Props) {
{metadata.artist}
</Text>
</Stack>
{showDifficultySelector && (
<HStack gap={0.5}>
<Select unfocusOnPress size="sm" collection={BEATMAP_LIST_COLLECTION} value={[selectedBeatmap.toString()]} onValueChange={handleBeatmapSelect} />
<Dialog
title="Create New Beatmap"
description="Add a new beatmap file to the mapset."
lazyMount
unmountOnExit
render={(ctx) => (
<CreateBeatmapForm dialog={ctx} onSubmit={(id, data) => dispatch(addBeatmap({ songId: sid, beatmapId: id, data: { ...data, lightshowId: id } }))}>
{(id) => (id ? `Create "${id}" beatmap` : `Create beatmap`)}
</CreateBeatmapForm>
)}
>
<Button variant="ghost" size="sm">
<PlusIcon size={16} />
</Button>
</Dialog>
</HStack>
)}
<HStack gap={0.5}>
<Select unfocusOnPress size="sm" collection={BEATMAP_LIST_COLLECTION} value={[selectedBeatmap.toString()]} onValueChange={handleBeatmapSelect} />
<Dialog
title="Create New Beatmap"
description="Add a new beatmap file to the mapset."
lazyMount
unmountOnExit
render={(ctx) => (
<CreateBeatmapForm dialog={ctx} onSubmit={(id, data) => dispatch(addBeatmap({ songId: sid, beatmapId: id, data: { ...data, lightshowId: id } }))}>
{(id) => (id ? `Create "${id}" beatmap` : `Create beatmap`)}
</CreateBeatmapForm>
)}
>
<Button variant="ghost" size="sm">
<PlusIcon size={16} />
</Button>
</Dialog>
</HStack>
</Stack>
</OuterWrapper>
);
Expand Down
6 changes: 3 additions & 3 deletions src/components/app/templates/error-boundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ function ErrorBoundary({ error, interactive = true, reset }: Props) {
<Container>
<Stack gap={3}>
<Stack gap={2}>
<Heading rank={1}>{error.name}</Heading>
<Text textStyle={"paragraph"}>{error.message}</Text>
{error instanceof Error && <Heading rank={1}>{error.name}</Heading>}
{error instanceof Error && <Text textStyle={"paragraph"}>{error.message}</Text>}
</Stack>
<Stack gap={2}>
<Heading rank={3}>Stack Trace</Heading>
{error.stack && (
{error instanceof Error && (
<StackWrapper>
{error.stack}
<Float placement="top-end" offset={"2"} className={css({ position: "sticky", alignSelf: "flex-start" })}>
Expand Down
2 changes: 1 addition & 1 deletion src/components/hooks/use-parent-dimensions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type RefObject, useCallback, useEffect, useRef, useState } from "react";

export function useParentDimensions<T extends Element>(): [ref: RefObject<T>, dimensions: { width: number; height: number }] {
export function useParentDimensions<T extends Element>(): [ref: RefObject<T | null>, dimensions: { width: number; height: number }] {
const ref = useRef<T>(null);

const [dimensions, setDimensions] = useState<{ width: number | null; height: number | null }>({ width: null, height: null });
Expand Down
26 changes: 15 additions & 11 deletions src/components/scene/hooks/use-object-placement.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { ThreeEvent } from "@react-three/fiber";
import type { EntityId } from "@reduxjs/toolkit";
import { useThrottledCallback } from "@tanstack/react-pacer/throttler";
import { useCallback, useRef } from "react";

import { useGlobalEventListener } from "$/components/hooks/use-global-event-listener";
import { finishManagingNoteSelection, startManagingNoteSelection } from "$/store/actions";
import { useAppDispatch, useAppSelector } from "$/store/hooks";
import { selectNotesEditorSelectionMode } from "$/store/selectors";
import { selectNotesEditorSelectionMode, selectPacerWait } from "$/store/selectors";
import { type App, ObjectSelectionMode } from "$/types";

interface UseObjectSelectionOptions<T extends App.IEditorObject> {
Expand All @@ -20,17 +22,18 @@ interface UseObjectSelectionOptions<T extends App.IEditorObject> {
export function useObjectPlacement<T extends App.IEditorObject>({ interactive, selectId, onItemSelect, onItemDeselect, onItemDelete, onItemModify, onItemWheel }: UseObjectSelectionOptions<T>) {
const dispatch = useAppDispatch();
const selectionMode = useAppSelector(selectNotesEditorSelectionMode);
const wait = useAppSelector(selectPacerWait);

const activePointerIdRef = useRef<number | null>(null);

const handlePointerDown = useCallback(
(event: PointerEvent, data: T) => {
(event: ThreeEvent<PointerEvent>, data: T) => {
if (!interactive) return;

if (activePointerIdRef.current === event.pointerId) return;
activePointerIdRef.current = event.pointerId;

event.stopPropagation();
event.nativeEvent.stopPropagation();

const id = selectId(data);
let newSelectionMode: ObjectSelectionMode | null = null;
Expand Down Expand Up @@ -81,9 +84,9 @@ export function useObjectPlacement<T extends App.IEditorObject>({ interactive, s
useGlobalEventListener("pointercancel", handlePointerUp, { shouldFire: !!selectionMode || activePointerIdRef.current !== null });

const handlePointerOver = useCallback(
(event: PointerEvent, data: T) => {
(event: ThreeEvent<PointerEvent>, data: T) => {
if (!interactive) return;
event.stopPropagation();
event.nativeEvent.stopPropagation();

if (!selectionMode) return;

Expand Down Expand Up @@ -112,15 +115,15 @@ export function useObjectPlacement<T extends App.IEditorObject>({ interactive, s
);

const handlePointerOut = useCallback(
(event: PointerEvent, _data: T) => {
(event: ThreeEvent<PointerEvent>, _data: T) => {
if (!interactive) return;
event.stopPropagation();
event.nativeEvent.stopPropagation();
},
[interactive],
);

const resolveWheelAction = useCallback(
(event: WheelEvent, data: T) => {
const resolveWheelAction = useThrottledCallback(
(event: ThreeEvent<WheelEvent>, data: T) => {
if (!interactive) return;
event.stopPropagation();

Expand All @@ -129,12 +132,13 @@ export function useObjectPlacement<T extends App.IEditorObject>({ interactive, s

onItemWheel?.(data, id, delta);
},
[interactive, selectId, onItemWheel],
{ wait: wait },
);

const handleWheel = useCallback(
(event: WheelEvent, data: T) => {
(event: ThreeEvent<WheelEvent>, data: T) => {
if (event.altKey) {
event.nativeEvent.stopPropagation();
resolveWheelAction(event, data);
}
},
Expand Down
11 changes: 7 additions & 4 deletions src/components/scene/layouts/visualization/for.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { EntityId } from "@reduxjs/toolkit";
import type { IWrapGridObject } from "bsmap";
import { type ComponentProps, type ReactNode, useMemo } from "react";
import type { Vector3Tuple } from "three";
Expand All @@ -7,23 +8,25 @@ import type { ObjectResolverOptions } from "$/components/scene/helpers";
import { HIGHEST_PRECISION } from "$/constants";
import { useVisualizationContext } from "./context";

interface Props<T extends IWrapGridObject> {
interface Props<T extends IWrapGridObject, Id extends EntityId> {
objects: T[];
resolveId: (model: T) => Id;
resolvePosition: (model: T, ctx: ObjectResolverOptions) => Vector3Tuple;
resolveColor: (model: T) => string;
children: (model: T, ctx: Pick<ComponentProps<"group">, "position" | "layers"> & { data: T; transparent: boolean; color: string }) => ReactNode;
children: (model: T, id: Id, ctx: Pick<ComponentProps<"group">, "position" | "layers"> & { data: T; transparent: boolean; color: string }) => ReactNode;
}
function VisualizationForGridObjects<T extends IWrapGridObject>({ objects, resolvePosition, resolveColor, children }: Props<T>) {
function VisualizationForGridObjects<T extends IWrapGridObject, Id extends EntityId>({ objects, resolveId, resolvePosition, resolveColor, children }: Props<T, Id>) {
const { cursorPosition, timescale, beatDepth } = useVisualizationContext();

const zPosition = useMemo(() => -SONG_OFFSET + (cursorPosition ?? 0) * beatDepth, [cursorPosition, beatDepth]);

const adjustment = useMemo(() => beatDepth * HIGHEST_PRECISION, [beatDepth]);

return objects.map((data) => {
const id = resolveId(data);
const position = resolvePosition(data, { timescale, beatDepth });
const noteZPosition = zPosition + position[2] - adjustment;
return children(data, {
return children(data, id, {
data,
position,
layers: 1,
Expand Down
Loading
Loading