From 51e8b1f4496308bb96fa5dbebd1bea8a1edc2b97 Mon Sep 17 00:00:00 2001 From: OLDREDSTONE Date: Thu, 15 Jan 2026 19:01:12 +0800 Subject: [PATCH 1/8] =?UTF-8?q?[RDView2]=20=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/appendix_tools.md | 34 +- pages/classicbeat.md | 2 +- script/{View.js => rdtkview.js} | 674 ++++++++++++++++++-------------- script/special.js | 90 +++-- 4 files changed, 437 insertions(+), 363 deletions(-) rename script/{View.js => rdtkview.js} (73%) diff --git a/pages/appendix_tools.md b/pages/appendix_tools.md index b9fe73d..f8fa85f 100644 --- a/pages/appendix_tools.md +++ b/pages/appendix_tools.md @@ -22,6 +22,8 @@ g 1 1 5 4 #0ff{ --- +完整功能支持请前往[此处](https://view.obugs.cn)。 +
diff --git a/pages/classicbeat.md b/pages/classicbeat.md index 40abb2c..2f7c987 100644 --- a/pages/classicbeat.md +++ b/pages/classicbeat.md @@ -10,7 +10,7 @@ 第二个选项“**摇摆**”就是剧情模式里老奶奶那样的摇摆普通拍子,可以使用拖动条来调节,对照下方绿色竖线的移动可以很直观地看到摇摆效果。不过拖动滑条你只能得到一些倍数十分规整的摇摆拍子,例如摇摆值为0.25,0.5,0.75等,如果你的音乐里真的有些更为不同寻常的摇摆幅度,那就要直接在框里填写数字了。 -```rdview2 8 9 +```rdtkview 8 9 {"beat": 2, "y": 1, "type": "AddClassicBeat", "row": 0, "tick": 1, "swing": 0.25, "hold": 0 }, {"beat": 2, "y": 2, "type": "AddClassicBeat", "row": 0, "tick": 1, "swing": 0.5, "hold": 0 }, {"beat": 2, "y": 3, "type": "AddClassicBeat", "row": 0, "tick": 1, "swing": 0.75, "hold": 0 }, diff --git a/script/View.js b/script/rdtkview.js similarity index 73% rename from script/View.js rename to script/rdtkview.js index 52c6413..a5aea5e 100644 --- a/script/View.js +++ b/script/rdtkview.js @@ -1,4 +1,4 @@ -// AssetManager.ts +// assetManager.ts var Point = class _Point { x = 0; y = 0; @@ -266,12 +266,34 @@ var Color = class _Color { return new _Color(this.a, this.r, this.g, blue); } }; +var canvas = new OffscreenCanvas(1, 1); +var blobs = /* @__PURE__ */ new Map(); var SliceInfo = class { bounds = new Rect(); center = new Rect(); pivot = new Point(); scale = 1; - blobUrl = ""; + async blobUrl() { + const key = `${this.bounds.left},${this.bounds.top},${this.bounds.width},${this.bounds.height}`; + const blob = blobs.get(key); + if (blob) { + return blob; + } else { + canvas.width = this.bounds.width; + canvas.height = this.bounds.height; + const ctx = canvas.getContext("2d"); + if (ctx === null) { + throw new Error("Failed to get 2D context"); + } + ctx.clearRect(0, 0, this.bounds.width, this.bounds.height); + ctx.drawImage(assetFile, this.bounds.left, this.bounds.top, this.bounds.width, this.bounds.height, 0, 0, this.bounds.width, this.bounds.height); + const blob2 = await canvas.convertToBlob({ + type: "image/png" + }); + blobs.set(key, URL.createObjectURL(blob2)); + return blobs.get(key); + } + } get isNinePatch() { return !this.center.isEmpty; } @@ -289,7 +311,6 @@ async function loadAssetFile() { }); } async function readFromStream(stream) { - const canvas = new OffscreenCanvas(1, 1); let offset = 0; const count = stream.getUint8(0); offset += 1; @@ -333,18 +354,6 @@ async function readFromStream(stream) { } sliceInfo.pivot = new Point(pivotLeft, pivotTop); } - canvas.width = width; - canvas.height = height; - const ctx = canvas.getContext("2d"); - if (ctx === null) { - throw new Error("Failed to get 2D context"); - } - ctx.clearRect(0, 0, width, height); - ctx.drawImage(assetFile, sliceInfo.bounds.left, sliceInfo.bounds.top, width, height, 0, 0, width, height); - const blob = await canvas.convertToBlob({ - type: "image/png" - }); - sliceInfo.blobUrl = URL.createObjectURL(blob); sliceInfos.set(key, sliceInfo); } return sliceInfos; @@ -355,15 +364,15 @@ var slices = await readFromStream(new DataView(await (await fetch(directoryPath assetLoaded = true; }); -// Consts.ts +// consts.ts var Tab = /* @__PURE__ */ function(Tab2) { - Tab2["Sounds"] = "sounds"; - Tab2["Rows"] = "rows"; - Tab2["Actions"] = "actions"; - Tab2["Decorations"] = "decorations"; - Tab2["Rooms"] = "rooms"; - Tab2["Windows"] = "windows"; - Tab2["Unknown"] = "unknown"; + Tab2["Sounds"] = "Sounds"; + Tab2["Rows"] = "Rows"; + Tab2["Actions"] = "Actions"; + Tab2["Decorations"] = "Sprites"; + Tab2["Rooms"] = "Rooms"; + Tab2["Windows"] = "Windows"; + Tab2["Unknown"] = "Unknown"; return Tab2; }({}); var SayReadyGetSetGoWords = /* @__PURE__ */ function(SayReadyGetSetGoWords2) { @@ -478,9 +487,18 @@ var EventType = /* @__PURE__ */ function(EventType2) { EventType2["Tile"] = "Tile"; EventType2["Tint"] = "Tint"; EventType2["TintRows"] = "TintRows"; + EventType2["Unknown"] = "Unknown"; EventType2["WindowResize"] = "WindowResize"; return EventType2; }({}); +var hiddenEventType = [ + EventType.ForwardDecorationEvent, + EventType.ForwardEvent, + EventType.ForwardRowEvent, + EventType.MacroEvent, + EventType.SpinningRows, + EventType.ShowSubdivisionsRows +]; var EventAttriblte = /* @__PURE__ */ function(EventAttriblte2) { EventAttriblte2[EventAttriblte2["None"] = 0] = "None"; EventAttriblte2[EventAttriblte2["DurationEvent"] = 1] = "DurationEvent"; @@ -545,29 +563,29 @@ var EventInfos = { AddFreeTimeBeat: new EventInfo(Tab.Rows), AddOneshotBeat: new EventInfo(Tab.Rows), AdvanceText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), - BassDrop: new EventInfo(Tab.Actions), + BassDrop: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), Blend: new EventInfo(Tab.Decorations), CallCustomMethod: new EventInfo(Tab.Actions), ChangeCharacter: new EventInfo(Tab.Actions), ChangePlayersRows: new EventInfo(Tab.Actions), Comment: new EventInfo(Tab.Unknown), - CustomFlash: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), + CustomFlash: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), DesktopColor: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent, "duration"), FadeRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), FinishLevel: new EventInfo(Tab.Actions), - Flash: new EventInfo(Tab.Actions), - FlipScreen: new EventInfo(Tab.Actions), + Flash: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + FlipScreen: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), FloatingText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), ForwardDecorationEvent: new EventInfo(Tab.Decorations), - ForwardEvent: new EventInfo(Tab.Unknown), + ForwardEvent: new EventInfo(Tab.Unknown, EventAttriblte.RoomEvent), ForwardRowEvent: new EventInfo(Tab.Rows), HideRow: new EventInfo(Tab.Actions), HideWindow: new EventInfo(Tab.Windows), - InvertColors: new EventInfo(Tab.Actions), + InvertColors: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), MacroEvent: new EventInfo(Tab.Unknown), MaskRoom: new EventInfo(Tab.Rooms), Move: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent, "duration"), - MoveCamera: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), + MoveCamera: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), MoveRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), MoveRow: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), NarrateRowInfo: new EventInfo(Tab.Sounds), @@ -577,15 +595,15 @@ var EventInfos = { PlayExpression: new EventInfo(Tab.Actions), PlaySong: new EventInfo(Tab.Sounds), PlaySound: new EventInfo(Tab.Sounds), - PulseCamera: new EventInfo(Tab.Actions), + PulseCamera: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), PulseFreeTimeBeat: new EventInfo(Tab.Rows), ReadNarration: new EventInfo(Tab.Sounds), RenameWindow: new EventInfo(Tab.Windows), ReorderRooms: new EventInfo(Tab.Rooms), - ReorderRow: new EventInfo(Tab.Rows), + ReorderRow: new EventInfo(Tab.Actions), ReorderSprite: new EventInfo(Tab.Decorations), ReorderWindows: new EventInfo(Tab.Windows), - SayReadyGetSetGo: new EventInfo(Tab.Sounds), + SayReadyGetSetGo: new EventInfo(Tab.Sounds, EventAttriblte.RoomEvent), SetBackgroundColor: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), SetBeatSound: new EventInfo(Tab.Sounds), SetBeatsPerMinute: new EventInfo(Tab.Sounds), @@ -594,7 +612,7 @@ var EventInfos = { SetCrotchetsPerBar: new EventInfo(Tab.Sounds), SetForeground: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), SetGameSound: new EventInfo(Tab.Sounds), - SetHandOwner: new EventInfo(Tab.Actions), + SetHandOwner: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), SetHeartExplodeInterval: new EventInfo(Tab.Sounds), SetHeartExplodeVolume: new EventInfo(Tab.Sounds), SetMainWindow: new EventInfo(Tab.Windows), @@ -610,22 +628,23 @@ var EventInfos = { SetWindowContent: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent, "duration"), ShakeScreen: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), ShakeScreenCustom: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - ShowDialogue: new EventInfo(Tab.Actions), - ShowHands: new EventInfo(Tab.Actions), + ShowDialogue: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + ShowHands: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), ShowRooms: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), ShowStatusSign: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), ShowSubdivisionsRows: new EventInfo(Tab.Actions), SpinningRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), - Stutter: new EventInfo(Tab.Actions), + Stutter: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), TagAction: new EventInfo(Tab.Actions), - TextExplosion: new EventInfo(Tab.Actions), + TextExplosion: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), Tile: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent, "duration"), Tint: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent, "duration"), TintRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + Unknown: new EventInfo(Tab.Unknown), WindowResize: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration") }; -// View.ts +// rdtkview.ts var lineHeight = 6; var charHeight = 8; var iconSize = 14; @@ -636,11 +655,37 @@ var IconStyle = class { scale = 1; showDuration = false; }; +var FilterData = class { + color; + hue = 0; + saturation = 1; + brightness = 1; + getFilter() { + let filter = ""; + if (this.color) { + filter += `url(#${getColorMatrixId(this.color)}) `; + } + if (this.hue !== 0) { + filter += `hue-rotate(${this.hue * 360}deg) `; + } + if (this.saturation !== 1) { + filter += `saturate(${this.saturation}) `; + } + if (this.brightness !== 1) { + filter += `brightness(${this.brightness}) `; + } + return filter.trim() || "none"; + } +}; function withState(color, active, enabled) { return (enabled ? color : new Color(4286874756)).withAlpha(active ? 192 : 91); } -function createLayer(key, bound, color, style) { +async function createLayer(key, bound, color, style) { const layer = document.createElement("div"); + layer.filterData = new FilterData(); + layer.updateFilter = () => { + layer.style.filter = layer.filterData.getFilter(); + }; const info = slices.get(key); layer.style.position = "absolute"; layer.style.boxSizing = "content-box"; @@ -652,7 +697,7 @@ function createLayer(key, bound, color, style) { layer.style.top = `${(bound?.top ?? bound?.y ?? 0) * style.scale}px`; layer.style.borderStyle = "solid"; layer.style.borderWidth = `${center.top * style.scale}px ${(info.bounds.width - center.right) * style.scale}px ${(info.bounds.height - center.bottom) * style.scale}px ${center.left * style.scale}px`; - layer.style.borderImageSource = `url(${info.blobUrl})`; + layer.style.borderImageSource = `url(${await info.blobUrl()})`; layer.style.borderImageSlice = `${center.top} ${info.bounds.width - center.right} ${info.bounds.height - center.bottom} ${center.left} fill`; layer.style.borderImageWidth = `1`; layer.style.borderImageOutset = `0`; @@ -666,7 +711,7 @@ function createLayer(key, bound, color, style) { layer.style.width = `${(bound.width ?? info?.bounds.width ?? 0) * style.scale}px`; layer.style.height = `${(bound.height ?? info?.bounds.height ?? 0) * style.scale}px`; if (info) { - layer.style.backgroundImage = `url(${info.blobUrl})`; + layer.style.backgroundImage = `url(${await info.blobUrl()})`; } layer.style.backgroundSize = `${(bound.width ?? info?.bounds.width ?? 0) * style.scale}px ${(bound.height ?? info?.bounds.height ?? 0) * style.scale}px`; } else { @@ -675,21 +720,20 @@ function createLayer(key, bound, color, style) { layer.style.width = `${(info?.bounds.width ?? 0) * style.scale}px`; layer.style.height = `${(info?.bounds.height ?? 0) * style.scale}px`; if (info) { - layer.style.backgroundImage = `url(${info.blobUrl})`; + layer.style.backgroundImage = `url(${await info.blobUrl()})`; } layer.style.backgroundSize = `${(info?.bounds.width ?? 0) * style.scale}px ${(info?.bounds.height ?? 0) * style.scale}px`; } } if (color && Color.White.equals(color) === false) { - const filterId = getColorMatrixId(color); - layer.style.filter = `url(#${filterId})`; layer.onColorChange = (color2) => { if (!color2) { return; } - const newFilterId = getColorMatrixId(color2); - layer.style.filter = `url(#${newFilterId})`; + layer.filterData.color = color2; + layer.updateFilter(); }; + layer.onColorChange(color); } else { } return layer; @@ -707,7 +751,7 @@ function getColorMatrixId(rgba) { const g = rgba.g / 255; const b = rgba.b / 255; const a = rgba.a / 255; - feColorMatrix.setAttribute("values", `${r} 0 0 0 0 0 ${g} 0 0 0 0 0 ${b} 0 0 0 0 0 ${a} 0`); + feColorMatrix.setAttribute("values", `${r * r} 0 0 0 0 0 ${g * g} 0 0 0 0 0 ${b * b} 0 0 0 0 0 ${a} 0`); const filter = document.createElementNS("http://www.w3.org/2000/svg", "filter"); filter.setAttribute("id", `filter_${rgba.toHexString()}`); filter.appendChild(feColorMatrix); @@ -734,10 +778,11 @@ function measureRDFontText(text) { } return len; } -function createRDFontLayer(text, style, color) { +async function createRDFontLayer(text, style, color) { const lineHead = new Point(0, -charHeight); const start = lineHead.clone(); const layer = document.createElement("div"); + const charLayers = []; layer.style.position = "absolute"; for (let i = 0; i < text.length; i++) { const char = text.charAt(i); @@ -749,25 +794,37 @@ function createRDFontLayer(text, style, color) { const charKey = `char_${charCode.toString(16).padStart(4, "0")}`; const charInfo = slices.get(charKey); if (charInfo) { - const charLayer = createLayer(charKey, new Point(start.x, start.y), color, style); + const charLayer = await createLayer(charKey, new Point(start.x, start.y), color, style); start.x += charInfo.bounds.width * style.scale; - layer.appendChild(charLayer); + charLayers.push(charLayer); } } } + layer.updateFilter = () => { + charLayers.forEach((cl) => { + cl.updateFilter(); + }); + }; + charLayers.forEach((cl) => { + layer.appendChild(cl); + }); return layer; } function createBackLayer(size, color, style) { const outline = "event_outline"; const back = "event_back"; - const backLayer = createLayer(back, new Rect(1, 1, (size?.width ?? iconSize) - 2, (size?.height ?? iconSize) - 2), withState(color, style.active, style.enabled), style); - const outlineLayer = createLayer(outline, size ? new Rect(size) : null, new Color(style.active ? 4294967295 : 4289243304), style); - if (backLayer.onColorChange) { - backLayer.onStateChange = (style2) => backLayer.onColorChange(withState(color, style2.active, style2.enabled)); - } - if (outlineLayer.onColorChange) { - outlineLayer.onStateChange = (style2) => outlineLayer.onColorChange(new Color(style2.active ? 4294967295 : 4289243304)); - } + const backLayer = createLayer(back, new Rect(1, 1, (size?.width ?? iconSize) - 2, (size?.height ?? iconSize) - 2), withState(color, style.active, style.enabled), style).then((layer) => { + if (layer.onColorChange) { + layer.onStateChange = (style2) => layer.onColorChange(withState(color, style2.active, style2.enabled)); + } + return layer; + }); + const outlineLayer = createLayer(outline, size ? new Rect(size) : null, new Color(style.active ? 4294967295 : 4289243304), style).then((layer) => { + if (layer.onColorChange) { + layer.onStateChange = (style2) => layer.onColorChange(new Color(style2.active ? 4294967295 : 4289243304)); + } + return layer; + }); return [ backLayer, outlineLayer @@ -833,26 +890,29 @@ function createHintLayer(hint, width, color) { }; return hintLayer; } -function createElementEvent(obj, style) { +async function createElementEvent(obj, style) { style = { ...new IconStyle(), ...style }; - const evttype = obj.type ?? EventType.ForwardEvent; let key0 = `event_${obj.type}`; + const hasType = EventType.hasOwnProperty(obj.type); + if (!hasType) { + console.warn(obj.type ? `Unknown event type: ${obj.type}` : `Event type missing`); + } if (!slices.has(key0)) { if (!slices.has("event_Unknown")) { return null; } key0 = "event_Unknown"; } - const info = slices.get(key0); - if (!info) { + const evttype = obj.type ?? EventType.Unknown; + const slcinfo = slices.get(key0) ?? slices.get("event_Unknown"); + if (!slcinfo) { console.warn(`Slice info for event type ${evttype} not found.`); return null; } - const evttypeEnum = EventType[evttype]; - const evinfo = EventInfos[evttypeEnum]; + const evinfo = EventInfos[evttype] ?? EventInfos[EventType.Unknown]; const key = "event_" + evttype; const pulse = "event_beat_pulse"; const hit = "event_beat_hit"; @@ -867,18 +927,10 @@ function createElementEvent(obj, style) { const evbskip = "event_beat_skip"; const beatColor = new Color(4284539717); const element = document.createElement("div"); - const internalLayers = []; - if (evttype === EventType.NewWindowDance) { - obj.tab = obj.customTab ?? Tab.Windows; - } - function addLayers(layers) { - for (const layer of layers) { - if (layer) { - element.appendChild(layer); - internalLayers.push(layer); - } - } - } + element.eventStyle = { + ...style + }; + const layersToAdd = []; element.style.imageRendering = "pixelated"; switch (evttype) { case EventType.AddClassicBeat: @@ -886,31 +938,30 @@ function createElementEvent(obj, style) { const tick = obj.tick ?? 1; const swing = (obj.swing ?? 0) || 1; const hold = obj.hold ?? 0; - const syncoSwing = obj.syncoSwing ?? 0; const prexs = obj.preXs ?? { syncoBeat: -1, syncoSwing: 0 }; const length = obj.length ?? 7; const iconWidth = iconSize * (tick * (length - 1 - prexs.syncoSwing)); - const holdBar = hold > 0 ? createLayer(evbarea, new Rect(iconWidth, 0, iconSize * hold, iconSize), new Color(style.active ? 4291839731 : 4286462352), style) : null; - if (holdBar) { - holdBar.style.pointerEvents = "none"; - } + const holdBar = hold > 0 ? createLayer(evbarea, new Rect(iconWidth, 0, iconSize * hold, iconSize), new Color(style.active ? 4291839731 : 4286462352), style).then((layer) => { + layer.style.pointerEvents = "none"; + return layer; + }) : null; const backLayers2 = createBackLayer(new Size(iconWidth, iconSize), colorOf(obj.tab ?? evinfo.defaultTab), style); const pulses = []; for (let i = 0; i < length - 1; i++) { - const pulseLayer = createLayer(pulse, new Point(iconSize * (tick * (i + i % 2 * (1 - swing) - (i <= prexs.syncoBeat ? 0 : prexs.syncoSwing))), 0), null, style); - layerHoverInit(pulseLayer); + const pulseLayer = createLayer(pulse, new Point(iconSize * (tick * (i + i % 2 * (1 - swing) - (i <= prexs.syncoBeat ? 0 : prexs.syncoSwing))), 0), null, style).then((layer) => { + layerHoverInit(layer); + return layer; + }); pulses.push(pulseLayer); } const hitLayer = createLayer(hit, new Point(iconSize * (tick * (length - 1 - (prexs.syncoSwing ?? 0))) - 1, 0), null, style); - addLayers([ - holdBar, - ...backLayers2, - ...pulses, - hitLayer - ]); + layersToAdd.push(holdBar); + layersToAdd.push(...backLayers2); + layersToAdd.push(...pulses); + layersToAdd.push(hitLayer); } break; case EventType.AddOneshotBeat: @@ -928,114 +979,119 @@ function createElementEvent(obj, style) { const off = interval - tick; const backLayers2 = createBackLayer(new Size(eventWidth, iconSize), colorOf(obj.tab ?? evinfo.defaultTab), style); const holdWidth = hold ? iconSize * (interval - tick - delay) : 0; - const holdLayer = hold && holdWidth - subdivWidth > 0 ? createLayer(evbarea, new Rect(eventWidth + subdivWidth, 0, holdWidth - subdivWidth, iconSize), new Color(style.enabled ? 4291839731 : 4285493103), style) : null; - const subdivLayer = subdiv > 1 ? createLayer(evbarea, new Rect(eventWidth, 0, subdivWidth, iconSize), new Color(style.enabled ? 4279480353 : 4285493103), style) : null; - const skipshotLayer = skip ? createLayer(evbarea, new Rect(eventWidth + Math.max(subdivWidth, holdWidth), 0, iconSize * (interval - delay) - Math.max(subdivWidth, holdWidth), iconSize), new Color(style.enabled ? 4291115835 : 4285493103), style) : null; - const skipHitLayer = skip ? createLayer(evbskip, new Point(eventWidth + iconSize * (interval - delay) - 1, 0), null, style) : null; - if (holdLayer) holdLayer.style.pointerEvents = "none"; - if (subdivLayer) subdivLayer.style.pointerEvents = "none"; - if (skipshotLayer) skipshotLayer.style.pointerEvents = "none"; - if (skipHitLayer) skipHitLayer.style.pointerEvents = "none"; + const holdLayer = hold && holdWidth - subdivWidth > 0 ? createLayer(evbarea, new Rect(eventWidth + subdivWidth, 0, holdWidth - subdivWidth, iconSize), new Color(style.enabled ? 4291839731 : 4285493103), style).then((layer) => { + layer.style.pointerEvents = "none"; + return layer; + }) : null; + const subdivLayer = subdiv > 1 ? createLayer(evbarea, new Rect(eventWidth, 0, subdivWidth, iconSize), new Color(style.enabled ? 4279480353 : 4285493103), style).then((layer) => { + layer.style.pointerEvents = "none"; + return layer; + }) : null; + const skipshotLayer = skip ? createLayer(evbarea, new Rect(eventWidth + Math.max(subdivWidth, holdWidth), 0, iconSize * (interval - delay) - Math.max(subdivWidth, holdWidth), iconSize), new Color(style.enabled ? 4291115835 : 4285493103), style).then((layer) => { + layer.style.pointerEvents = "none"; + return layer; + }) : null; + const skipHitLayer = skip ? createLayer(evbskip, new Point(eventWidth + iconSize * (interval - delay) - 1, 0), null, style).then((layer) => { + layer.style.pointerEvents = "none"; + return layer; + }) : null; const pulses = []; const crossLayers = []; const posx = -off * iconSize; - const hittype = mode === "Freezeshot" ? hitf : hitb; + const hittype = mode === "Freezeshot" ? hitf : mode === "Burnshot" ? hitb : null; for (let l = 0; l <= loop; l++) { for (let i = 0; i < subdiv; i++) { - const pulseLayer = createLayer(pulse, new Point(iconSize * (l * interval + i * tick / subdiv), 0), null, style); - layerHoverInit(pulseLayer); + const pulseLayer = createLayer(pulse, new Point(iconSize * (l * interval + i * tick / subdiv), 0), null, style).then((layer) => { + layerHoverInit(layer); + return layer; + }); pulses.push(pulseLayer); } for (let i = 0; i < subdiv; i++) { const hitLayer2 = createLayer(hit, new Point(iconSize * (l * interval + delay + tick + i * tick / subdiv) - 1, 0), null, style); pulses.push(hitLayer2); } - const crossLayer1 = mode || hold ? createLayer(beatcross, new Point(iconSize * l * interval + posx - 1, 0), null, style) : null; - const crossLayer2 = mode ? createLayer(beatcross, new Point(iconSize * (l - (mode === "Freezeshot" ? 0 : 1)) * interval - 1, 0), null, style) : null; - const hitLayer = createLayer(hittype, new Point(iconSize * (l * interval + tick) - 1, 0), null, style); - if (crossLayer1) { - layerHoverInit(crossLayer1); - crossLayers.push(crossLayer1); - } - if (crossLayer2) { - layerHoverInit(crossLayer2); - crossLayers.push(crossLayer2); - } + const crossLayer1 = mode || hold ? createLayer(beatcross, new Point(iconSize * l * interval + posx - 1, 0), null, style).then((layer) => { + layerHoverInit(layer); + return layer; + }) : null; + const crossLayer2 = mode ? createLayer(beatcross, new Point(iconSize * (l - (mode === "Freezeshot" ? 0 : 1)) * interval - 1, 0), null, style).then((layer) => { + layerHoverInit(layer); + return layer; + }) : null; + const hitLayer = hittype ? createLayer(hittype, new Point(iconSize * (l * interval + tick) - 1, 0), null, style) : null; + crossLayers.push(crossLayer1); + crossLayers.push(crossLayer2); pulses.push(hitLayer); } - const loopLayer = createLayer("event_beat_loop", new Point(eventWidth, 0), null, style); - loopLayer.style.opacity = "0"; - loopLayer.style.zIndex = "5"; - loopLayer.onStateChange = (style2) => { - if (style2.hover) { - loopLayer.style.opacity = "1.0"; - } else { - loopLayer.style.opacity = "0"; - } - }; - addLayers([ - ...backLayers2, - holdLayer, - subdivLayer, - skipshotLayer, - skipHitLayer, - ...pulses, - loopLayer, - ...crossLayers - ]); + const loopLayer = createLayer("event_beat_loop", new Point(eventWidth, 0), null, style).then((loopLayer2) => { + loopLayer2.style.opacity = "0"; + loopLayer2.style.zIndex = "5"; + loopLayer2.onStateChange = (style2) => { + if (style2.hover) { + loopLayer2.style.opacity = "1.0"; + } else { + loopLayer2.style.opacity = "0"; + } + }; + return loopLayer2; + }); + layersToAdd.push(...backLayers2); + layersToAdd.push(holdLayer); + layersToAdd.push(subdivLayer); + layersToAdd.push(skipshotLayer); + layersToAdd.push(skipHitLayer); + layersToAdd.push(...pulses); + layersToAdd.push(loopLayer); + layersToAdd.push(...crossLayers); } break; case EventType.AddFreeTimeBeat: { const hold = obj.hold ?? 0; - const holdLayer = hold > 0 ? createLayer(evbarea, new Rect(info.bounds.width, 0, iconSize * hold - info.bounds.width, iconSize), new Color(style.active ? 4291839731 : 4286462352), style) : null; - if (holdLayer) { - holdLayer.style.pointerEvents = "none"; - } - const backLayers2 = createBackLayer(new Size(info.bounds.width, iconSize), beatColor, style); + const holdLayer = hold > 0 ? createLayer(evbarea, new Rect(slcinfo.bounds.width, 0, iconSize * hold - slcinfo.bounds.width, iconSize), new Color(style.active ? 4291839731 : 4286462352), style).then((layer) => { + layer.style.pointerEvents = "none"; + return layer; + }) : null; + const backLayers2 = createBackLayer(new Size(slcinfo.bounds.width, iconSize), beatColor, style); const hitLayer = obj.pulse === 6 ? createLayer(hit, new Point(0, 0), null, style) : null; - const textLayer = createRDFontLayer(((obj.pulse ?? 0) + 1).toString(), style, null); - textLayer.style.left = `${1.5 * style.scale}px`; - textLayer.style.top = `${10 * style.scale}px`; - addLayers([ - holdLayer, - ...backLayers2, - hitLayer, - textLayer - ]); + const textLayer = createRDFontLayer(((obj.pulse ?? 0) + 1).toString(), style, null).then((textLayer2) => { + textLayer2.style.left = `${1.5 * style.scale}px`; + textLayer2.style.top = `${10 * style.scale}px`; + return textLayer2; + }); + layersToAdd.push(holdLayer); + layersToAdd.push(...backLayers2); + layersToAdd.push(hitLayer); + layersToAdd.push(textLayer); } break; case EventType.Comment: { - const backLayers2 = createBackLayer(info.bounds.size, new Color(obj.color ?? "7d7d7d"), style); + const backLayers2 = createBackLayer(slcinfo.bounds.size, new Color(obj.color ?? "7d7d7d"), style); const iconLayer = createLayer(key, null, null, style); - addLayers([ - ...backLayers2, - iconLayer - ]); + layersToAdd.push(...backLayers2); + layersToAdd.push(iconLayer); } break; case EventType.DesktopColor: { - const backLayers2 = createBackLayer(info.bounds.size, colorOf(obj.tab ?? evinfo.defaultTab), style); - console.log(info.bounds.size); + const backLayers2 = createBackLayer(slcinfo.bounds.size, colorOf(obj.tab ?? evinfo.defaultTab), style); const iconColorLayer = createLayer(`${key}_0`, new Point(0, iconSize), new Color(obj.endColor ?? "ffffff"), style); const iconLayer = createLayer(`${key}_1`, new Point(0, iconSize), null, style); - addLayers([ - ...backLayers2, - iconColorLayer, - iconLayer - ]); + layersToAdd.push(...backLayers2); + layersToAdd.push(iconColorLayer); + layersToAdd.push(iconLayer); } break; case EventType.PulseFreeTimeBeat: { const hold = obj.hold ?? 0; - const holdLayer = hold > 0 ? createLayer(evbarea, new Rect(info.bounds.width, 0, iconSize * hold - info.bounds.width, info.bounds.height), new Color(style.active ? 4291839731 : 4286462352), style) : null; - if (holdLayer) { - holdLayer.style.pointerEvents = "none"; - } - const backLayers2 = createBackLayer(new Size(info.bounds.width, info.bounds.height), beatColor, style); + const holdLayer = hold > 0 ? createLayer(evbarea, new Rect(slcinfo.bounds.width, 0, iconSize * hold - slcinfo.bounds.width, slcinfo.bounds.height), new Color(style.active ? 4291839731 : 4286462352), style).then((layer) => { + layer.style.pointerEvents = "none"; + return layer; + }) : null; + const backLayers2 = createBackLayer(new Size(slcinfo.bounds.width, slcinfo.bounds.height), beatColor, style); const hitLayer = obj.pulse === 6 ? createLayer(hit, new Point(0, 0), null, style) : null; let text = ""; switch (obj.action) { @@ -1052,21 +1108,21 @@ function createElementEvent(obj, style) { text = "x"; break; } - const textLayer = createRDFontLayer(text, style, null); - textLayer.style.left = `${1.5 * style.scale}px`; - textLayer.style.top = `${10 * style.scale}px`; - addLayers([ - holdLayer, - ...backLayers2, - hitLayer, - textLayer - ]); + const textLayer = createRDFontLayer(text, style, null).then((textLayer2) => { + textLayer2.style.left = `${1.5 * style.scale}px`; + textLayer2.style.top = `${10 * style.scale}px`; + return textLayer2; + }); + layersToAdd.push(holdLayer); + layersToAdd.push(...backLayers2); + layersToAdd.push(hitLayer); + layersToAdd.push(textLayer); } break; case EventType.ReorderRooms: case EventType.ReorderWindows: { - const backLayers2 = createBackLayer(info.bounds.size, colorOf(obj.tab ?? evinfo.defaultTab), style); + const backLayers2 = createBackLayer(slcinfo.bounds.size, colorOf(obj.tab ?? evinfo.defaultTab), style); const orderLayers = []; const order = obj.order ?? [ 0, @@ -1080,10 +1136,8 @@ function createElementEvent(obj, style) { orderLayers.push(orderLayer); } } - addLayers([ - ...backLayers2, - ...orderLayers - ]); + layersToAdd.push(...backLayers2); + layersToAdd.push(...orderLayers); } break; case EventType.SayReadyGetSetGo: @@ -1117,38 +1171,36 @@ function createElementEvent(obj, style) { const wordLayer = createRDFontLayer(line, { ...style, scale: style.scale / 2 - }, null); - wordLayer.style.left = `${p.x * style.scale}px`; - wordLayer.style.top = `${p.y * style.scale}px`; + }, null).then((wordLayer2) => { + wordLayer2.style.left = `${p.x * style.scale}px`; + wordLayer2.style.top = `${p.y * style.scale}px`; + return wordLayer2; + }); wordLayers.push(wordLayer); } - addLayers([ - ...backLayers2, - ...wordLayers - ]); + layersToAdd.push(...backLayers2); + layersToAdd.push(...wordLayers); } break; case EventType.SetRowXs: { const syncoBeat = obj.syncoBeat ?? -1; - const width = info.bounds.width / 6; + const width = slcinfo.bounds.width / 6; const iconBounds = slices.get(beatx).bounds; const s = width / iconBounds.width; let left = 0; const top = iconSize / 2 - iconBounds.height * s / 2; const patternLayers = []; - const backLayers2 = createBackLayer(new Size(info.bounds.width, info.bounds.height), colorOf(obj.tab ?? evinfo.defaultTab), style); - for (let p of obj.pattern) { + const backLayers2 = createBackLayer(new Size(slcinfo.bounds.width, slcinfo.bounds.height), colorOf(obj.tab ?? evinfo.defaultTab), style); + for (let p of obj.pattern ?? "------") { const beatxLayer = createLayer(p === "x" ? beatx : beatline, new Rect(left, top, width, iconBounds.height * s), null, style); patternLayers.push(beatxLayer); left += width; } const syncoBeatLayer = syncoBeat >= 0 ? createLayer(beatsynco, new Rect(width * syncoBeat, top, width, iconBounds.height * s), null, style) : null; - addLayers([ - ...backLayers2, - ...patternLayers, - syncoBeatLayer - ]); + layersToAdd.push(...backLayers2); + layersToAdd.push(...patternLayers); + layersToAdd.push(syncoBeatLayer); } break; case EventType.ShowRooms: @@ -1156,49 +1208,41 @@ function createElementEvent(obj, style) { const backLayers2 = createBackLayer(new Size(iconSize, iconSize * 4), colorOf(obj.tab ?? evinfo.defaultTab), style); const roomLayers = []; for (let i = 0; i < 4; i++) { - const roomLayer = createLayer(`${key}_${obj.rooms.indexOf(i) >= 0 ? "1" : "0"}`, new Point(0, i * iconSize * style.scale), null, { + const roomLayer = createLayer(`${key}_${(obj.rooms ?? []).indexOf(i) >= 0 ? "1" : "0"}`, new Point(0, i * iconSize * style.scale), null, { ...style, scale: style.scale / 2 }); roomLayers.push(roomLayer); } - addLayers([ - ...backLayers2, - ...roomLayers - ]); + layersToAdd.push(...backLayers2); + layersToAdd.push(...roomLayers); } break; default: - const backLayers = createBackLayer(info.bounds.size, colorOf(obj.tab ?? evinfo.defaultTab), style); - addLayers(backLayers); + const backLayers = createBackLayer(slcinfo.bounds.size, colorOf(obj.tab ?? evinfo.defaultTab), style); + layersToAdd.push(...backLayers); switch (evttype) { case EventType.CustomFlash: const iconLayer = createLayer(key, null, null, style); const startColorLayer = createLayer(`${key}_0`, null, new Color(obj.startColor ?? "000000").withAlpha((obj.startOpacity ?? 0) * 255), style); const endColorLayer = createLayer(`${key}_1`, null, new Color(obj.endColor ?? "000000").withAlpha((obj.endOpacity ?? 0) * 255), style); - addLayers([ - iconLayer, - startColorLayer, - endColorLayer - ]); + layersToAdd.push(iconLayer); + layersToAdd.push(startColorLayer); + layersToAdd.push(endColorLayer); break; case EventType.FlipScreen: { const flip = (obj.flipX ? 1 : 0) | (obj.flipY ? 2 : 0); const iconLayer2 = createLayer(flip === 0 ? `${key}_0` : `${key}_${flip - 1}`, null, null, style); - addLayers([ - iconLayer2 - ]); + layersToAdd.push(iconLayer2); } break; case EventType.FloatingText: { const backColorLayer = createLayer(`${key}_0`, null, Color.FromRgba(obj.color ?? "FFFFFFFF"), style); const foreColorLayer = createLayer(`${key}_1`, null, Color.FromRgba(obj.outlineColor ?? "FFFFFFFF"), style); - addLayers([ - backColorLayer, - foreColorLayer - ]); + layersToAdd.push(backColorLayer); + layersToAdd.push(foreColorLayer); } break; case EventType.MoveRoom: @@ -1213,7 +1257,10 @@ function createElementEvent(obj, style) { const uniform = Math.sqrt(width * width + height * height); width /= uniform; height /= uniform; - const roomLayer = createLayer(key, new Rect(iconSize / 2, iconSize / 2, iconSize * width, iconSize * height), null, style); + const roomLayer = createLayer(key, new Rect(iconSize / 2, iconSize / 2, iconSize * width, iconSize * height), null, style).then((roomLayer2) => { + roomLayer2.style.transform = `translate(-50%, -50%) rotate(${-degree}deg)`; + return roomLayer2; + }); let pivotx = width * (1 - pleft * 2); let pivoty = height * (1 - ptop * 2); const widthrotated = pivotx * Math.cos(radius) + pivoty * Math.sin(radius); @@ -1225,11 +1272,8 @@ function createElementEvent(obj, style) { pointLayer.style.left = `${iconSize * (1 - widthrotated) * style.scale / 2}px`; pointLayer.style.top = `${iconSize * (1 + heightrotated) * style.scale / 2}px`; pointLayer.style.backgroundColor = "#FF0000"; - roomLayer.style.transform = `translate(-50%, -50%) rotate(${-degree}deg)`; - addLayers([ - roomLayer, - pointLayer - ]); + layersToAdd.push(roomLayer); + layersToAdd.push(Promise.resolve(pointLayer)); } break; case EventType.PaintHands: @@ -1239,10 +1283,8 @@ function createElementEvent(obj, style) { const border = obj.border; const backColorLayer = createLayer(key, null, Color.FromRgba(obj.tintColor ?? "FFFFFFFF"), style); const foreColorLayer = border ? createLayer(border === "Outline" ? `${key}_0` : border === "Glow" ? `${key}_1` : "", null, Color.FromRgba(obj.borderColor ?? "FFFFFFFF"), style) : null; - addLayers([ - backColorLayer, - foreColorLayer - ]); + layersToAdd.push(backColorLayer); + layersToAdd.push(foreColorLayer); } break; case EventType.SetBackgroundColor: @@ -1253,34 +1295,36 @@ function createElementEvent(obj, style) { const imagePath = images.length > 0 ? images[0] : ""; const contentInfo = slices.get(`${key}_1`); const colorLayer = createLayer(`${key}_0`, null, Color.FromRgba((backType === "Color" ? obj.color : null) ?? "FFFFFF"), style); - const contentLayer = backType === "Image" ? createLayer("", contentInfo?.bounds ? new Rect(contentInfo?.bounds.size) : null, null, style) : null; - if (backType === "Image" && contentLayer) { - contentLayer.style.backgroundImage = `url(${imagePath})`; - contentLayer.style.left = `${-(contentInfo?.pivot.x ?? 0) * style.scale}px`; - contentLayer.style.top = `${-(contentInfo?.pivot.y ?? 0) * style.scale}px`; - } - addLayers([ - iconLayer2, - colorLayer, - contentLayer - ]); + const contentLayer = backType === "Image" ? createLayer("", contentInfo?.bounds ? new Rect(contentInfo?.bounds.size) : null, null, style).then((contentLayer2) => { + if (backType === "Image" && contentLayer2) { + contentLayer2.style.backgroundImage = `url(${imagePath})`; + contentLayer2.style.left = `${-(contentInfo?.pivot.x ?? 0) * style.scale}px`; + contentLayer2.style.top = `${-(contentInfo?.pivot.y ?? 0) * style.scale}px`; + } + return contentLayer2; + }) : null; + layersToAdd.push(iconLayer2); + layersToAdd.push(colorLayer); + layersToAdd.push(contentLayer); } break; case EventType.SetCrotchetsPerBar: { const cpb = obj.crotchetsPerBar ?? 0; const iconLayer2 = createLayer(key, null, null, style); - const cpbLayer = createRDFontLayer(cpb > 9 ? "-" : cpb.toString(), style, Color.Black); - const bLayer = createRDFontLayer("4", style, Color.Black); - cpbLayer.style.left = `${2 * style.scale}px`; - cpbLayer.style.top = `${9 * style.scale}px`; - bLayer.style.left = `${8 * style.scale}px`; - bLayer.style.top = `${14 * style.scale}px`; - addLayers([ - iconLayer2, - cpbLayer, - bLayer - ]); + const cpbLayer = createRDFontLayer(cpb > 9 ? "-" : cpb.toString(), style, Color.Black).then((cpbLayer2) => { + cpbLayer2.style.left = `${2 * style.scale}px`; + cpbLayer2.style.top = `${9 * style.scale}px`; + return cpbLayer2; + }); + const bLayer = createRDFontLayer("4", style, Color.Black).then((bLayer2) => { + bLayer2.style.left = `${8 * style.scale}px`; + bLayer2.style.top = `${14 * style.scale}px`; + return bLayer2; + }); + layersToAdd.push(iconLayer2); + layersToAdd.push(cpbLayer); + layersToAdd.push(bLayer); } break; case EventType.SetForeground: @@ -1290,24 +1334,22 @@ function createElementEvent(obj, style) { const imagePath = images.length > 0 ? images[0] : ""; const contentInfo = slices.get(`${key}_1`); const colorLayer = imagePath ? createLayer(`${key}_0`, null, Color.Black, style) : null; - const contentLayer = imagePath ? createLayer("", contentInfo?.bounds ? new Rect(contentInfo?.bounds.size) : null, null, style) : null; - if (contentLayer) { - contentLayer.style.backgroundImage = `url(${imagePath})`; - contentLayer.style.left = `${-(contentInfo?.pivot.x ?? 0) * style.scale}px`; - contentLayer.style.top = `${-(contentInfo?.pivot.y ?? 0) * style.scale}px`; - } - addLayers([ - iconLayer2, - colorLayer, - contentLayer - ]); + const contentLayer = imagePath ? createLayer("", contentInfo?.bounds ? new Rect(contentInfo?.bounds.size) : null, null, style).then((contentLayer2) => { + if (contentLayer2) { + contentLayer2.style.backgroundImage = `url(${imagePath})`; + contentLayer2.style.left = `${-(contentInfo?.pivot.x ?? 0) * style.scale}px`; + contentLayer2.style.top = `${-(contentInfo?.pivot.y ?? 0) * style.scale}px`; + } + return contentLayer2; + }) : null; + layersToAdd.push(iconLayer2); + layersToAdd.push(colorLayer); + layersToAdd.push(contentLayer); } break; default: - const layer = createLayer(key, null, null, style); - addLayers([ - layer - ]); + const layer = createLayer(hasType ? key : "event_Unknown", null, null, style); + layersToAdd.push(layer); break; } break; @@ -1315,14 +1357,12 @@ function createElementEvent(obj, style) { if (evinfo.isDurationEvent) { const duration = obj[evinfo.durationKey] ?? 0; const durWidth = iconSize * duration; - const durationLayer = durWidth > info.bounds.width ? createLayer(evbarea, new Rect(info.bounds.width, 0, durWidth - info.bounds.width, info.bounds.height), colorOf(obj.tab ?? evinfo.defaultTab), style) : null; - if (durationLayer) { - durationLayer.style.pointerEvents = "none"; - layerHoverInit(durationLayer); - } - addLayers([ - durationLayer - ]); + const durationLayer = durWidth > slcinfo.bounds.width ? createLayer(evbarea, new Rect(slcinfo.bounds.width, 0, durWidth - slcinfo.bounds.width, slcinfo.bounds.height), colorOf(obj.tab ?? evinfo.defaultTab), style).then((layer) => { + layer.style.pointerEvents = "none"; + layerHoverInit(layer); + return layer; + }) : null; + layersToAdd.push(durationLayer); } const rooms = obj.rooms ?? []; const roomEnabled = new Color(4292392977); @@ -1330,37 +1370,36 @@ function createElementEvent(obj, style) { if (evinfo.isRoomEvent) { const roomLayers = []; for (let i = 0; i < 4; i++) { - const roomLayer = createLayer(`room_${i}`, new Point(iconSize, 0), rooms.indexOf(i) > -1 ? roomEnabled : roomDisabled, style); - if (roomLayer) { - layerHoverInit(roomLayer); - } + const roomLayer = createLayer(`room_${i}`, new Point(iconSize, 0), rooms.indexOf(i) > -1 ? roomEnabled : roomDisabled, style).then((roomLayer2) => { + if (roomLayer2) { + layerHoverInit(roomLayer2); + } + return roomLayer2; + }); roomLayers.push(roomLayer); } - const roomTopLayer = rooms.indexOf(4) > -1 ? createLayer(`room_top`, new Point(iconSize, 0), roomEnabled, style) : null; - if (roomTopLayer) { - layerHoverInit(roomTopLayer); - } + const roomTopLayer = rooms.indexOf(4) > -1 ? createLayer(`room_top`, new Point(iconSize, 0), roomEnabled, style).then((roomTopLayer2) => { + if (roomTopLayer2) { + layerHoverInit(roomTopLayer2); + } + return roomTopLayer2; + }) : null; roomLayers.push(roomTopLayer); - addLayers(roomLayers); + layersToAdd.push(...roomLayers); } const condition = obj.if ?? ""; if (condition.length > 0) { const positive = /(? 0 ? `Error: Unknown type: ${obj.type}` : "Error: Type missing", slcinfo.bounds.width * style.scale, colorOf(obj.tab ?? evinfo.defaultTab)); + } + break; + } + if (hintLayer) { + layersToAdd.push(Promise.resolve(hintLayer)); + } + if (obj["$style"]) { + const hsb = obj["$style"].hsb ?? [ + 0, + 0, + 0 + ]; + if (hsb[0] !== 0 || hsb[1] !== 0 || hsb[2] !== 0) { + layersToAdd.forEach((layer) => layer?.then((layer2) => { + layer2.filterData.hue = hsb[0]; + layer2.filterData.saturation = hsb[1]; + layer2.filterData.brightness = hsb[2]; + })); + } + layersToAdd.forEach((layer) => layer?.then((layer2) => { + layer2.updateFilter(); + })); } element.onStateChange = (style2) => { style2 = { ...style2 }; - internalLayers.forEach((layer) => { - if (layer.onStateChange) { - layer.onStateChange(style2); + layersToAdd.forEach((layer) => layer?.then((layer2) => { + if (layer2.onStateChange) { + layer2.onStateChange(style2); } - }); + })); }; + element.moveTo = function(x, y) { + this.style.left = `${x}px`; + this.style.top = `${y}px`; + }; + for await (const layer of layersToAdd) { + if (layer) { + element.appendChild(layer); + } + } + element.eventData = obj; return element; } export { + IconStyle, + colorOf, createElementEvent }; diff --git a/script/special.js b/script/special.js index 1bf3445..536258a 100644 --- a/script/special.js +++ b/script/special.js @@ -1,4 +1,4 @@ -import { createElementEvent } from "./View.js"; +import { createElementEvent } from "./rdtkview.js"; let curx = 0; let cury = 0; @@ -322,52 +322,58 @@ function rdview2() { } const eventStyle = { "scale": 2.0, "showDuration": false }; let maxy = 0; + const elemPromises = []; for (let obj of objs) { const style = { ...eventStyle, enabled: obj.active ?? true }; - const elem = createElementEvent(obj, style); - elem.eventStyle = style; - elem.style.position = "absolute"; - elem.style.left = `${ - ((((obj.bar ?? 1) - 1) * 8) + (obj.beat ?? 1) - 1) * 14 * - eventStyle.scale - }px`; - elem.style.top = `${ - (obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale - }px`; - if ( - ((obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale) + - elem.offsetHeight > maxy - ) { - maxy = ((obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale) + - elem.offsetHeight; - } - elem.addEventListener("mousedown", (event) => { - const eStyle = elem.eventStyle; - eStyle.active = true; - elem.onStateChange(eStyle); + const elem = createElementEvent(obj, style).then((elem) => { + elem.eventStyle = style; + elem.style.position = "absolute"; + elem.style.left = `${ + ((((obj.bar ?? 1) - 1) * 8) + (obj.beat ?? 1) - 1) * 14 * + eventStyle.scale + }px`; + elem.style.top = `${ + (obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale + }px`; + if ( + ((obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale) + + elem.offsetHeight > maxy + ) { + maxy = ((obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale) + + elem.offsetHeight; + } + elem.addEventListener("mousedown", (event) => { + const eStyle = elem.eventStyle; + eStyle.active = true; + elem.onStateChange(eStyle); + }); + elem.addEventListener("mouseover", (event) => { + const eStyle = elem.eventStyle; + eStyle.hover = true; + elem.onStateChange(eStyle); + }); + elem.addEventListener("mouseout", (event) => { + const eStyle = elem.eventStyle; + eStyle.hover = false; + eStyle.active = false; + elem.onStateChange(eStyle); + }); + elem.addEventListener("mouseup", (event) => { + const eStyle = elem.eventStyle; + eStyle.active = false; + elem.onStateChange(eStyle); + }); + return elem; }); - elem.addEventListener("mouseover", (event) => { - const eStyle = elem.eventStyle; - eStyle.hover = true; - elem.onStateChange(eStyle); + elemPromises.push(elem); + Promise.all(elemPromises).then((elems) => { + elems.forEach((elem) => { + rdcanvas.appendChild(elem); + }); }); - elem.addEventListener("mouseout", (event) => { - const eStyle = elem.eventStyle; - eStyle.hover = false; - eStyle.active = false; - elem.onStateChange(eStyle); - }); - elem.addEventListener("mouseup", (event) => { - const eStyle = elem.eventStyle; - eStyle.active = false; - elem.onStateChange(eStyle); - }); - rdcanvas.style.position = "relative"; - rdcanvas.style.height = `${maxy + 4 * 14 * eventStyle.scale}px`; - if (elem) { - rdcanvas.appendChild(elem); - } } + rdcanvas.style.position = "relative"; + rdcanvas.style.height = `${maxy + 4 * 14 * eventStyle.scale}px`; } initCanvas(); initLineNumbers(); From 4e1e57b08eea09ed90a2d44d64bfc21bc549ae1c Mon Sep 17 00:00:00 2001 From: OLDREDSTONE Date: Fri, 16 Jan 2026 20:07:12 +0800 Subject: [PATCH 2/8] =?UTF-8?q?[RDView]=20=E7=8E=B0=E5=B7=B2=E5=8F=AF?= =?UTF-8?q?=E7=94=A8=EF=BC=8C=E5=9C=A8=20pages/classicbeat=20=E5=8F=AF?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E7=AC=AC=E4=B8=80=E4=B8=AA=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 44 +- rdviewAssets/assets | Bin 0 -> 4326 bytes script/rdtkview.js | 1156 ++++++++++++++++++++----------------- script/rdtkview_render.js | 82 +++ script/special.js | 10 +- 5 files changed, 727 insertions(+), 565 deletions(-) create mode 100644 rdviewAssets/assets create mode 100644 script/rdtkview_render.js diff --git a/index.html b/index.html index 552e396..5461011 100644 --- a/index.html +++ b/index.html @@ -35,7 +35,8 @@ }; - + diff --git a/rdviewAssets/assets b/rdviewAssets/assets new file mode 100644 index 0000000000000000000000000000000000000000..2c1e294273840c8a547aecb8dd5761cf9caa2b25 GIT binary patch literal 4326 zcmZ`-&2Jk;6yK0Gq=C2v(w0&e)D}u{RM_>m`4CQ=E-fMu#ipq^u$tYS*h|(k%kDZ( z5waq2podh-v5Gi?$gQ{BH~}rE`~|&L0&(Ua;LYyX^U|c3Xn*g$dEam5#ecs{*C~sw z1sbizJZNyAhkxWU&!3EmZFvr7R>XVEjRy9EvFQ;l$EQHT?JoJE80AB<&2 z#E|oDbPrC>j7TnZct{f2dj}NsJ?4Ved!RsR?Xfk+`|KxBF)5T;;NmsUsee6@puFzQ z*LnI~5Z`|KZHVty`mKxa6&YnS@EG%0dl@Y4w)V$fNrP|Fc#(K)C2`@8?EaV(U#5(7 zsU&Ci$7T-a%F-WA?AHG~iev17rc>#W8=fom?17#$DRG(d(4}FjKe7q|cyu%?ADGW# z8A0_~EIr7Ld_HI^fC@{OC1Y8X$|~64!cmO84GtW|Fl;b?6hpVcxXf>(7sb45`XuUD z`W76JSy?1b$ghk3%Yt2*bd!gD61oXF1LSO)EJm|S@>Hs;<@wYE_(BTjeac)7u#89MtQmw}OshaYo60piWQ{hR zkW!Y0yazduv5xZG&%ptivCl~e!$863n{1U2Ali`y;-*ZPsx57Q>;#OW@ZB6S>%?z?bHfRy@h32oiDvr%SvZrB10c&W5`KUWF^qh|8URbC9#~&6 z8g+QQLe^;(rc(CNoa>rU!IsyhLgfSP(Jy-eGoNKOm#scJG$oVApm+`}zMoU92PY6g_LJD^84Win1%Ao5b0J2YfF zKpl1%?WaAyK$t@{FgKh%zD^sE$&d`7AEk~Y!jx))4%v(?x{+2af@W-?06VUItQc5+!>RThGj7STZNz*!l(D2x|*woj{YT%}*!fiMkGK*8EN z%^YIN`(qJW*90S~C6kef@A%XPD~c@K`J&Hg*iy!q;Gu~VKTXw);yla*w2DY^6^bmA zvj|lZZfW4lkVK+2LCQj6WinE!{*LnLCR?W=^gg`i(XPsxc!nU?InXA(G<`2fZ!F8$ zRf#h_=0%;)ptJlfup>vl(IKo&g|m<)QL_Q?q+9bOiWWj1Y=Jd7eGTIKX;&`NxWnB6 zuw+XK9dpd0mvwxo(9!;nn zFCMr5oO|xYbVL%`#wGh-?S#`Ip{472<5=(#G7&SF%~VpO?^QS}N&wONdazM-;Pu=5x>#SN9~f?LIieu&X(9qBCU+NP>X(U{m& z(H8SBU{pA@sVo$WGniL8hk4}-7*#G}$?6r1YO`39yoY&q5hJIDCEbs(*R+8pS8pIx z(zUxPqLOhOqx=*`g_9T+XYQ(KOQlyauY3Wc%B8z1gQe)N)`QZ~l7RkY>&Bu0hlZ52_u_!8!o&R|qNk0mQ_U|#i2jB4*} ztBx#_S?r7bE|zo(Skf(RtDKeT2Uv2oj!;F{?yHC@#&L}DQ}uzm-qG@PfANUdX2HM|0y?Ji5aiJ_|Rs z+{#AMtFW7WM<>Otj%`M3UNG}Ck%W}wydO4y#*)6rXb}`kH_+N-89T5F9ex<~Js?Zx z)O)#mq-=f<9wxa6nLda2jkU$XW9d8ah8@K)c7Y*{s^!4aO?WL2lMNH3UrTENd(2ZC zqoudNt7o%~l@I@_KanXtu!vg5%BR29pU8(&>|~Z+1rIR6sDf>ohvC*{={b;knrP%e za#?{BlbC;NT?d&pCco`yUc_xTF98 literal 0 HcmV?d00001 diff --git a/script/rdtkview.js b/script/rdtkview.js index a5aea5e..be302b6 100644 --- a/script/rdtkview.js +++ b/script/rdtkview.js @@ -1,4 +1,282 @@ -// assetManager.ts +// definition.ts +var Tab = /* @__PURE__ */ function(Tab2) { + Tab2["Sounds"] = "Sounds"; + Tab2["Rows"] = "Rows"; + Tab2["Actions"] = "Actions"; + Tab2["Decorations"] = "Sprites"; + Tab2["Rooms"] = "Rooms"; + Tab2["Windows"] = "Windows"; + Tab2["Unknown"] = "Unknown"; + return Tab2; +}(Tab || {}); +var SayReadyGetSetGoWords = /* @__PURE__ */ function(SayReadyGetSetGoWords2) { + SayReadyGetSetGoWords2["SayReaDyGetSetGoNew"] = "SayReaDyGetSetGoNew"; + SayReadyGetSetGoWords2["SayReaDyGetSetOne"] = "SayReaDyGetSetOne"; + SayReadyGetSetGoWords2["SayGetSetGo"] = "SayGetSetGo"; + SayReadyGetSetGoWords2["SayGetSetOne"] = "SayGetSetOne"; + SayReadyGetSetGoWords2["JustSayRea"] = "JustSayRea"; + SayReadyGetSetGoWords2["JustSayDy"] = "JustSayDy"; + SayReadyGetSetGoWords2["JustSayGet"] = "JustSayGet"; + SayReadyGetSetGoWords2["JustSaySet"] = "JustSaySet"; + SayReadyGetSetGoWords2["JustSayAnd"] = "JustSayAnd"; + SayReadyGetSetGoWords2["JustSayGo"] = "JustSayGo"; + SayReadyGetSetGoWords2["JustSayStop"] = "JustSayStop"; + SayReadyGetSetGoWords2["JustSayAndStop"] = "JustSayAndStop"; + SayReadyGetSetGoWords2["SaySwitch"] = "SaySwitch"; + SayReadyGetSetGoWords2["SayWatch"] = "SayWatch"; + SayReadyGetSetGoWords2["SayListen"] = "SayListen"; + SayReadyGetSetGoWords2["Count1"] = "Count1"; + SayReadyGetSetGoWords2["Count2"] = "Count2"; + SayReadyGetSetGoWords2["Count3"] = "Count3"; + SayReadyGetSetGoWords2["Count4"] = "Count4"; + SayReadyGetSetGoWords2["Count5"] = "Count5"; + SayReadyGetSetGoWords2["Count6"] = "Count6"; + SayReadyGetSetGoWords2["Count7"] = "Count7"; + SayReadyGetSetGoWords2["Count8"] = "Count8"; + SayReadyGetSetGoWords2["Count9"] = "Count9"; + SayReadyGetSetGoWords2["Count10"] = "Count10"; + SayReadyGetSetGoWords2["SayReadyGetSetGo"] = "SayReadyGetSetGo"; + SayReadyGetSetGoWords2["JustSayReady"] = "JustSayReady"; + return SayReadyGetSetGoWords2; +}(SayReadyGetSetGoWords || {}); +var EventType = /* @__PURE__ */ function(EventType2) { + EventType2["AddClassicBeat"] = "AddClassicBeat"; + EventType2["AddFreeTimeBeat"] = "AddFreeTimeBeat"; + EventType2["AddOneshotBeat"] = "AddOneshotBeat"; + EventType2["AdvanceText"] = "AdvanceText"; + EventType2["BassDrop"] = "BassDrop"; + EventType2["Blend"] = "Blend"; + EventType2["CallCustomMethod"] = "CallCustomMethod"; + EventType2["ChangeCharacter"] = "ChangeCharacter"; + EventType2["ChangePlayersRows"] = "ChangePlayersRows"; + EventType2["Comment"] = "Comment"; + EventType2["CustomFlash"] = "CustomFlash"; + EventType2["DesktopColor"] = "DesktopColor"; + EventType2["FadeRoom"] = "FadeRoom"; + EventType2["FinishLevel"] = "FinishLevel"; + EventType2["Flash"] = "Flash"; + EventType2["FlipScreen"] = "FlipScreen"; + EventType2["FloatingText"] = "FloatingText"; + EventType2["ForwardDecorationEvent"] = "ForwardDecorationEvent"; + EventType2["ForwardEvent"] = "ForwardEvent"; + EventType2["ForwardRowEvent"] = "ForwardRowEvent"; + EventType2["HideRow"] = "HideRow"; + EventType2["HideWindow"] = "HideWindow"; + EventType2["InvertColors"] = "InvertColors"; + EventType2["MacroEvent"] = "MacroEvent"; + EventType2["MaskRoom"] = "MaskRoom"; + EventType2["Move"] = "Move"; + EventType2["MoveCamera"] = "MoveCamera"; + EventType2["MoveRoom"] = "MoveRoom"; + EventType2["MoveRow"] = "MoveRow"; + EventType2["NarrateRowInfo"] = "NarrateRowInfo"; + EventType2["NewWindowDance"] = "NewWindowDance"; + EventType2["PaintHands"] = "PaintHands"; + EventType2["PlayAnimation"] = "PlayAnimation"; + EventType2["PlayExpression"] = "PlayExpression"; + EventType2["PlaySong"] = "PlaySong"; + EventType2["PlaySound"] = "PlaySound"; + EventType2["PulseCamera"] = "PulseCamera"; + EventType2["PulseFreeTimeBeat"] = "PulseFreeTimeBeat"; + EventType2["ReadNarration"] = "ReadNarration"; + EventType2["RenameWindow"] = "RenameWindow"; + EventType2["ReorderRooms"] = "ReorderRooms"; + EventType2["ReorderRow"] = "ReorderRow"; + EventType2["ReorderSprite"] = "ReorderSprite"; + EventType2["ReorderWindows"] = "ReorderWindows"; + EventType2["SayReadyGetSetGo"] = "SayReadyGetSetGo"; + EventType2["SetBackgroundColor"] = "SetBackgroundColor"; + EventType2["SetBeatSound"] = "SetBeatSound"; + EventType2["SetBeatsPerMinute"] = "SetBeatsPerMinute"; + EventType2["SetClapSounds"] = "SetClapSounds"; + EventType2["SetCountingSound"] = "SetCountingSound"; + EventType2["SetCrotchetsPerBar"] = "SetCrotchetsPerBar"; + EventType2["SetForeground"] = "SetForeground"; + EventType2["SetGameSound"] = "SetGameSound"; + EventType2["SetHandOwner"] = "SetHandOwner"; + EventType2["SetHeartExplodeInterval"] = "SetHeartExplodeInterval"; + EventType2["SetHeartExplodeVolume"] = "SetHeartExplodeVolume"; + EventType2["SetMainWindow"] = "SetMainWindow"; + EventType2["SetOneshotWave"] = "SetOneshotWave"; + EventType2["SetPlayStyle"] = "SetPlayStyle"; + EventType2["SetRoomContentMode"] = "SetRoomContentMode"; + EventType2["SetRoomPerspective"] = "SetRoomPerspective"; + EventType2["SetRowXs"] = "SetRowXs"; + EventType2["SetSpeed"] = "SetSpeed"; + EventType2["SetTheme"] = "SetTheme"; + EventType2["SetVFXPreset"] = "SetVFXPreset"; + EventType2["SetVisible"] = "SetVisible"; + EventType2["SetWindowContent"] = "SetWindowContent"; + EventType2["ShakeScreen"] = "ShakeScreen"; + EventType2["ShakeScreenCustom"] = "ShakeScreenCustom"; + EventType2["ShowDialogue"] = "ShowDialogue"; + EventType2["ShowHands"] = "ShowHands"; + EventType2["ShowRooms"] = "ShowRooms"; + EventType2["ShowStatusSign"] = "ShowStatusSign"; + EventType2["ShowSubdivisionsRows"] = "ShowSubdivisionsRows"; + EventType2["SpinningRows"] = "SpinningRows"; + EventType2["Stutter"] = "Stutter"; + EventType2["TagAction"] = "TagAction"; + EventType2["TextExplosion"] = "TextExplosion"; + EventType2["Tile"] = "Tile"; + EventType2["Tint"] = "Tint"; + EventType2["TintRows"] = "TintRows"; + EventType2["Unknown"] = "Unknown"; + EventType2["WindowResize"] = "WindowResize"; + return EventType2; +}(EventType || {}); +var hiddenEventType = [ + EventType.ForwardDecorationEvent, + EventType.ForwardEvent, + EventType.ForwardRowEvent, + EventType.MacroEvent, + EventType.SpinningRows, + EventType.ShowSubdivisionsRows +]; +var EventAttriblte = /* @__PURE__ */ function(EventAttriblte2) { + EventAttriblte2[EventAttriblte2["None"] = 0] = "None"; + EventAttriblte2[EventAttriblte2["DurationEvent"] = 1] = "DurationEvent"; + EventAttriblte2[EventAttriblte2["RoomEvent"] = 2] = "RoomEvent"; + return EventAttriblte2; +}(EventAttriblte || {}); +var EventInfo = class { + defaultTab; + durationKey = "duration"; + attr; + get isDurationEvent() { + return (this.attr & EventAttriblte.DurationEvent) !== 0; + } + get isRoomEvent() { + return (this.attr & EventAttriblte.RoomEvent) !== 0; + } + constructor(tab, enumAttriblte, durationKey) { + this.defaultTab = tab; + this.attr = enumAttriblte ?? EventAttriblte.None; + this.durationKey = durationKey ?? "duration"; + } +}; +var WordInfo = class { + phrase; + length; + constructor(phrase, length) { + this.phrase = phrase; + this.length = length; + } +}; +var WordInfos = { + SayReaDyGetSetGoNew: new WordInfo("Rea, Dy, Get, Set, Go!", 4), + SayReaDyGetSetOne: new WordInfo("Rea, Dy, Get, Set, One!", 4), + SayGetSetGo: new WordInfo("Get, Set, Go!", 2), + SayGetSetOne: new WordInfo("Get, Set, One!", 2), + JustSayRea: new WordInfo("Rea", 0), + JustSayDy: new WordInfo("Dy", 0), + JustSayGet: new WordInfo("Get", 0), + JustSaySet: new WordInfo("Set", 0), + JustSayAnd: new WordInfo("And", 0), + JustSayGo: new WordInfo("Go!", 0), + JustSayStop: new WordInfo("Stop", 0), + JustSayAndStop: new WordInfo("And Stop!", 0), + SaySwitch: new WordInfo("Switch", 0), + SayWatch: new WordInfo("Watch", 0), + SayListen: new WordInfo("Listen", 0), + Count1: new WordInfo("1", 0), + Count2: new WordInfo("2", 0), + Count3: new WordInfo("3", 0), + Count4: new WordInfo("4", 0), + Count5: new WordInfo("5", 0), + Count6: new WordInfo("6", 0), + Count7: new WordInfo("7", 0), + Count8: new WordInfo("8", 0), + Count9: new WordInfo("9", 0), + Count10: new WordInfo("10", 0), + SayReadyGetSetGo: new WordInfo("Ready, Get, Set, Go!", 4), + JustSayReady: new WordInfo("Ready", 0) +}; +var EventInfos = { + AddClassicBeat: new EventInfo(Tab.Rows), + AddFreeTimeBeat: new EventInfo(Tab.Rows), + AddOneshotBeat: new EventInfo(Tab.Rows), + AdvanceText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), + BassDrop: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + Blend: new EventInfo(Tab.Decorations), + CallCustomMethod: new EventInfo(Tab.Actions), + ChangeCharacter: new EventInfo(Tab.Actions), + ChangePlayersRows: new EventInfo(Tab.Actions), + Comment: new EventInfo(Tab.Unknown), + CustomFlash: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + DesktopColor: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent, "duration"), + FadeRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), + FinishLevel: new EventInfo(Tab.Actions), + Flash: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + FlipScreen: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + FloatingText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + ForwardDecorationEvent: new EventInfo(Tab.Decorations), + ForwardEvent: new EventInfo(Tab.Unknown, EventAttriblte.RoomEvent), + ForwardRowEvent: new EventInfo(Tab.Rows), + HideRow: new EventInfo(Tab.Actions), + HideWindow: new EventInfo(Tab.Windows), + InvertColors: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + MacroEvent: new EventInfo(Tab.Unknown), + MaskRoom: new EventInfo(Tab.Rooms), + Move: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent, "duration"), + MoveCamera: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + MoveRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), + MoveRow: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), + NarrateRowInfo: new EventInfo(Tab.Sounds), + NewWindowDance: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), + PaintHands: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + PlayAnimation: new EventInfo(Tab.Decorations), + PlayExpression: new EventInfo(Tab.Actions), + PlaySong: new EventInfo(Tab.Sounds), + PlaySound: new EventInfo(Tab.Sounds), + PulseCamera: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + PulseFreeTimeBeat: new EventInfo(Tab.Rows), + ReadNarration: new EventInfo(Tab.Sounds), + RenameWindow: new EventInfo(Tab.Windows), + ReorderRooms: new EventInfo(Tab.Rooms), + ReorderRow: new EventInfo(Tab.Actions), + ReorderSprite: new EventInfo(Tab.Decorations), + ReorderWindows: new EventInfo(Tab.Windows), + SayReadyGetSetGo: new EventInfo(Tab.Sounds, EventAttriblte.RoomEvent), + SetBackgroundColor: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + SetBeatSound: new EventInfo(Tab.Sounds), + SetBeatsPerMinute: new EventInfo(Tab.Sounds), + SetClapSounds: new EventInfo(Tab.Sounds), + SetCountingSound: new EventInfo(Tab.Sounds), + SetCrotchetsPerBar: new EventInfo(Tab.Sounds), + SetForeground: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + SetGameSound: new EventInfo(Tab.Sounds), + SetHandOwner: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + SetHeartExplodeInterval: new EventInfo(Tab.Sounds), + SetHeartExplodeVolume: new EventInfo(Tab.Sounds), + SetMainWindow: new EventInfo(Tab.Windows), + SetOneshotWave: new EventInfo(Tab.Rows), + SetPlayStyle: new EventInfo(Tab.Actions), + SetRoomContentMode: new EventInfo(Tab.Rooms), + SetRoomPerspective: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), + SetRowXs: new EventInfo(Tab.Rows), + SetSpeed: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), + SetTheme: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + SetVFXPreset: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + SetVisible: new EventInfo(Tab.Decorations), + SetWindowContent: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent, "duration"), + ShakeScreen: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + ShakeScreenCustom: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + ShowDialogue: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + ShowHands: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + ShowRooms: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), + ShowStatusSign: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), + ShowSubdivisionsRows: new EventInfo(Tab.Actions), + SpinningRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), + Stutter: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + TagAction: new EventInfo(Tab.Actions), + TextExplosion: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), + Tile: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent, "duration"), + Tint: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent, "duration"), + TintRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), + Unknown: new EventInfo(Tab.Unknown), + WindowResize: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration") +}; var Point = class _Point { x = 0; y = 0; @@ -266,50 +544,22 @@ var Color = class _Color { return new _Color(this.a, this.r, this.g, blue); } }; -var canvas = new OffscreenCanvas(1, 1); -var blobs = /* @__PURE__ */ new Map(); var SliceInfo = class { bounds = new Rect(); center = new Rect(); pivot = new Point(); scale = 1; - async blobUrl() { - const key = `${this.bounds.left},${this.bounds.top},${this.bounds.width},${this.bounds.height}`; - const blob = blobs.get(key); - if (blob) { - return blob; - } else { - canvas.width = this.bounds.width; - canvas.height = this.bounds.height; - const ctx = canvas.getContext("2d"); - if (ctx === null) { - throw new Error("Failed to get 2D context"); - } - ctx.clearRect(0, 0, this.bounds.width, this.bounds.height); - ctx.drawImage(assetFile, this.bounds.left, this.bounds.top, this.bounds.width, this.bounds.height, 0, 0, this.bounds.width, this.bounds.height); - const blob2 = await canvas.convertToBlob({ - type: "image/png" - }); - blobs.set(key, URL.createObjectURL(blob2)); - return blobs.get(key); - } - } get isNinePatch() { return !this.center.isEmpty; } }; + +// assetManager.ts var assetFilePath = "assets.png"; var slicesFilePath = "assets.bin"; var directoryPath = "./rdviewAssets"; -async function loadAssetFile() { - const pngPath = directoryPath + "/" + assetFilePath; - return await new Promise((resolve, reject) => { - const img = new Image(); - img.onload = () => resolve(img); - img.onerror = (e) => reject(new Error(`Failed to load asset file: ${pngPath}`)); - img.src = pngPath; - }); -} +var assetSize = new Size(210, 160); +var assetUrl = directoryPath + "/" + assetFilePath; async function readFromStream(stream) { let offset = 0; const count = stream.getUint8(0); @@ -359,291 +609,10 @@ async function readFromStream(stream) { return sliceInfos; } var assetLoaded = false; -var assetFile = await loadAssetFile(); var slices = await readFromStream(new DataView(await (await fetch(directoryPath + "/" + slicesFilePath)).arrayBuffer())).finally(() => { assetLoaded = true; }); -// consts.ts -var Tab = /* @__PURE__ */ function(Tab2) { - Tab2["Sounds"] = "Sounds"; - Tab2["Rows"] = "Rows"; - Tab2["Actions"] = "Actions"; - Tab2["Decorations"] = "Sprites"; - Tab2["Rooms"] = "Rooms"; - Tab2["Windows"] = "Windows"; - Tab2["Unknown"] = "Unknown"; - return Tab2; -}({}); -var SayReadyGetSetGoWords = /* @__PURE__ */ function(SayReadyGetSetGoWords2) { - SayReadyGetSetGoWords2["SayReaDyGetSetGoNew"] = "SayReaDyGetSetGoNew"; - SayReadyGetSetGoWords2["SayReaDyGetSetOne"] = "SayReaDyGetSetOne"; - SayReadyGetSetGoWords2["SayGetSetGo"] = "SayGetSetGo"; - SayReadyGetSetGoWords2["SayGetSetOne"] = "SayGetSetOne"; - SayReadyGetSetGoWords2["JustSayRea"] = "JustSayRea"; - SayReadyGetSetGoWords2["JustSayDy"] = "JustSayDy"; - SayReadyGetSetGoWords2["JustSayGet"] = "JustSayGet"; - SayReadyGetSetGoWords2["JustSaySet"] = "JustSaySet"; - SayReadyGetSetGoWords2["JustSayAnd"] = "JustSayAnd"; - SayReadyGetSetGoWords2["JustSayGo"] = "JustSayGo"; - SayReadyGetSetGoWords2["JustSayStop"] = "JustSayStop"; - SayReadyGetSetGoWords2["JustSayAndStop"] = "JustSayAndStop"; - SayReadyGetSetGoWords2["SaySwitch"] = "SaySwitch"; - SayReadyGetSetGoWords2["SayWatch"] = "SayWatch"; - SayReadyGetSetGoWords2["SayListen"] = "SayListen"; - SayReadyGetSetGoWords2["Count1"] = "Count1"; - SayReadyGetSetGoWords2["Count2"] = "Count2"; - SayReadyGetSetGoWords2["Count3"] = "Count3"; - SayReadyGetSetGoWords2["Count4"] = "Count4"; - SayReadyGetSetGoWords2["Count5"] = "Count5"; - SayReadyGetSetGoWords2["Count6"] = "Count6"; - SayReadyGetSetGoWords2["Count7"] = "Count7"; - SayReadyGetSetGoWords2["Count8"] = "Count8"; - SayReadyGetSetGoWords2["Count9"] = "Count9"; - SayReadyGetSetGoWords2["Count10"] = "Count10"; - SayReadyGetSetGoWords2["SayReadyGetSetGo"] = "SayReadyGetSetGo"; - SayReadyGetSetGoWords2["JustSayReady"] = "JustSayReady"; - return SayReadyGetSetGoWords2; -}({}); -var EventType = /* @__PURE__ */ function(EventType2) { - EventType2["AddClassicBeat"] = "AddClassicBeat"; - EventType2["AddFreeTimeBeat"] = "AddFreeTimeBeat"; - EventType2["AddOneshotBeat"] = "AddOneshotBeat"; - EventType2["AdvanceText"] = "AdvanceText"; - EventType2["BassDrop"] = "BassDrop"; - EventType2["Blend"] = "Blend"; - EventType2["CallCustomMethod"] = "CallCustomMethod"; - EventType2["ChangeCharacter"] = "ChangeCharacter"; - EventType2["ChangePlayersRows"] = "ChangePlayersRows"; - EventType2["Comment"] = "Comment"; - EventType2["CustomFlash"] = "CustomFlash"; - EventType2["DesktopColor"] = "DesktopColor"; - EventType2["FadeRoom"] = "FadeRoom"; - EventType2["FinishLevel"] = "FinishLevel"; - EventType2["Flash"] = "Flash"; - EventType2["FlipScreen"] = "FlipScreen"; - EventType2["FloatingText"] = "FloatingText"; - EventType2["ForwardDecorationEvent"] = "ForwardDecorationEvent"; - EventType2["ForwardEvent"] = "ForwardEvent"; - EventType2["ForwardRowEvent"] = "ForwardRowEvent"; - EventType2["HideRow"] = "HideRow"; - EventType2["HideWindow"] = "HideWindow"; - EventType2["InvertColors"] = "InvertColors"; - EventType2["MacroEvent"] = "MacroEvent"; - EventType2["MaskRoom"] = "MaskRoom"; - EventType2["Move"] = "Move"; - EventType2["MoveCamera"] = "MoveCamera"; - EventType2["MoveRoom"] = "MoveRoom"; - EventType2["MoveRow"] = "MoveRow"; - EventType2["NarrateRowInfo"] = "NarrateRowInfo"; - EventType2["NewWindowDance"] = "NewWindowDance"; - EventType2["PaintHands"] = "PaintHands"; - EventType2["PlayAnimation"] = "PlayAnimation"; - EventType2["PlayExpression"] = "PlayExpression"; - EventType2["PlaySong"] = "PlaySong"; - EventType2["PlaySound"] = "PlaySound"; - EventType2["PulseCamera"] = "PulseCamera"; - EventType2["PulseFreeTimeBeat"] = "PulseFreeTimeBeat"; - EventType2["ReadNarration"] = "ReadNarration"; - EventType2["RenameWindow"] = "RenameWindow"; - EventType2["ReorderRooms"] = "ReorderRooms"; - EventType2["ReorderRow"] = "ReorderRow"; - EventType2["ReorderSprite"] = "ReorderSprite"; - EventType2["ReorderWindows"] = "ReorderWindows"; - EventType2["SayReadyGetSetGo"] = "SayReadyGetSetGo"; - EventType2["SetBackgroundColor"] = "SetBackgroundColor"; - EventType2["SetBeatSound"] = "SetBeatSound"; - EventType2["SetBeatsPerMinute"] = "SetBeatsPerMinute"; - EventType2["SetClapSounds"] = "SetClapSounds"; - EventType2["SetCountingSound"] = "SetCountingSound"; - EventType2["SetCrotchetsPerBar"] = "SetCrotchetsPerBar"; - EventType2["SetForeground"] = "SetForeground"; - EventType2["SetGameSound"] = "SetGameSound"; - EventType2["SetHandOwner"] = "SetHandOwner"; - EventType2["SetHeartExplodeInterval"] = "SetHeartExplodeInterval"; - EventType2["SetHeartExplodeVolume"] = "SetHeartExplodeVolume"; - EventType2["SetMainWindow"] = "SetMainWindow"; - EventType2["SetOneshotWave"] = "SetOneshotWave"; - EventType2["SetPlayStyle"] = "SetPlayStyle"; - EventType2["SetRoomContentMode"] = "SetRoomContentMode"; - EventType2["SetRoomPerspective"] = "SetRoomPerspective"; - EventType2["SetRowXs"] = "SetRowXs"; - EventType2["SetSpeed"] = "SetSpeed"; - EventType2["SetTheme"] = "SetTheme"; - EventType2["SetVFXPreset"] = "SetVFXPreset"; - EventType2["SetVisible"] = "SetVisible"; - EventType2["SetWindowContent"] = "SetWindowContent"; - EventType2["ShakeScreen"] = "ShakeScreen"; - EventType2["ShakeScreenCustom"] = "ShakeScreenCustom"; - EventType2["ShowDialogue"] = "ShowDialogue"; - EventType2["ShowHands"] = "ShowHands"; - EventType2["ShowRooms"] = "ShowRooms"; - EventType2["ShowStatusSign"] = "ShowStatusSign"; - EventType2["ShowSubdivisionsRows"] = "ShowSubdivisionsRows"; - EventType2["SpinningRows"] = "SpinningRows"; - EventType2["Stutter"] = "Stutter"; - EventType2["TagAction"] = "TagAction"; - EventType2["TextExplosion"] = "TextExplosion"; - EventType2["Tile"] = "Tile"; - EventType2["Tint"] = "Tint"; - EventType2["TintRows"] = "TintRows"; - EventType2["Unknown"] = "Unknown"; - EventType2["WindowResize"] = "WindowResize"; - return EventType2; -}({}); -var hiddenEventType = [ - EventType.ForwardDecorationEvent, - EventType.ForwardEvent, - EventType.ForwardRowEvent, - EventType.MacroEvent, - EventType.SpinningRows, - EventType.ShowSubdivisionsRows -]; -var EventAttriblte = /* @__PURE__ */ function(EventAttriblte2) { - EventAttriblte2[EventAttriblte2["None"] = 0] = "None"; - EventAttriblte2[EventAttriblte2["DurationEvent"] = 1] = "DurationEvent"; - EventAttriblte2[EventAttriblte2["RoomEvent"] = 2] = "RoomEvent"; - return EventAttriblte2; -}({}); -var EventInfo = class { - defaultTab; - durationKey = "duration"; - attr; - get isDurationEvent() { - return (this.attr & EventAttriblte.DurationEvent) !== 0; - } - get isRoomEvent() { - return (this.attr & EventAttriblte.RoomEvent) !== 0; - } - constructor(tab, enumAttriblte, durationKey) { - this.defaultTab = tab; - this.attr = enumAttriblte ?? EventAttriblte.None; - this.durationKey = durationKey ?? "duration"; - } -}; -var WordInfo = class { - phrase; - length; - constructor(phrase, length) { - this.phrase = phrase; - this.length = length; - } -}; -var WordInfos = { - SayReaDyGetSetGoNew: new WordInfo("Rea, Dy, Get, Set, Go!", 4), - SayReaDyGetSetOne: new WordInfo("Rea, Dy, Get, Set, One!", 4), - SayGetSetGo: new WordInfo("Get, Set, Go!", 2), - SayGetSetOne: new WordInfo("Get, Set, One!", 2), - JustSayRea: new WordInfo("Rea", 0), - JustSayDy: new WordInfo("Dy", 0), - JustSayGet: new WordInfo("Get", 0), - JustSaySet: new WordInfo("Set", 0), - JustSayAnd: new WordInfo("And", 0), - JustSayGo: new WordInfo("Go!", 0), - JustSayStop: new WordInfo("Stop", 0), - JustSayAndStop: new WordInfo("And Stop!", 0), - SaySwitch: new WordInfo("Switch", 0), - SayWatch: new WordInfo("Watch", 0), - SayListen: new WordInfo("Listen", 0), - Count1: new WordInfo("1", 0), - Count2: new WordInfo("2", 0), - Count3: new WordInfo("3", 0), - Count4: new WordInfo("4", 0), - Count5: new WordInfo("5", 0), - Count6: new WordInfo("6", 0), - Count7: new WordInfo("7", 0), - Count8: new WordInfo("8", 0), - Count9: new WordInfo("9", 0), - Count10: new WordInfo("10", 0), - SayReadyGetSetGo: new WordInfo("Ready, Get, Set, Go!", 4), - JustSayReady: new WordInfo("Ready", 0) -}; -var EventInfos = { - AddClassicBeat: new EventInfo(Tab.Rows), - AddFreeTimeBeat: new EventInfo(Tab.Rows), - AddOneshotBeat: new EventInfo(Tab.Rows), - AdvanceText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), - BassDrop: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - Blend: new EventInfo(Tab.Decorations), - CallCustomMethod: new EventInfo(Tab.Actions), - ChangeCharacter: new EventInfo(Tab.Actions), - ChangePlayersRows: new EventInfo(Tab.Actions), - Comment: new EventInfo(Tab.Unknown), - CustomFlash: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - DesktopColor: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent, "duration"), - FadeRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), - FinishLevel: new EventInfo(Tab.Actions), - Flash: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - FlipScreen: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - FloatingText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - ForwardDecorationEvent: new EventInfo(Tab.Decorations), - ForwardEvent: new EventInfo(Tab.Unknown, EventAttriblte.RoomEvent), - ForwardRowEvent: new EventInfo(Tab.Rows), - HideRow: new EventInfo(Tab.Actions), - HideWindow: new EventInfo(Tab.Windows), - InvertColors: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - MacroEvent: new EventInfo(Tab.Unknown), - MaskRoom: new EventInfo(Tab.Rooms), - Move: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent, "duration"), - MoveCamera: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - MoveRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), - MoveRow: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), - NarrateRowInfo: new EventInfo(Tab.Sounds), - NewWindowDance: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), - PaintHands: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - PlayAnimation: new EventInfo(Tab.Decorations), - PlayExpression: new EventInfo(Tab.Actions), - PlaySong: new EventInfo(Tab.Sounds), - PlaySound: new EventInfo(Tab.Sounds), - PulseCamera: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - PulseFreeTimeBeat: new EventInfo(Tab.Rows), - ReadNarration: new EventInfo(Tab.Sounds), - RenameWindow: new EventInfo(Tab.Windows), - ReorderRooms: new EventInfo(Tab.Rooms), - ReorderRow: new EventInfo(Tab.Actions), - ReorderSprite: new EventInfo(Tab.Decorations), - ReorderWindows: new EventInfo(Tab.Windows), - SayReadyGetSetGo: new EventInfo(Tab.Sounds, EventAttriblte.RoomEvent), - SetBackgroundColor: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - SetBeatSound: new EventInfo(Tab.Sounds), - SetBeatsPerMinute: new EventInfo(Tab.Sounds), - SetClapSounds: new EventInfo(Tab.Sounds), - SetCountingSound: new EventInfo(Tab.Sounds), - SetCrotchetsPerBar: new EventInfo(Tab.Sounds), - SetForeground: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - SetGameSound: new EventInfo(Tab.Sounds), - SetHandOwner: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - SetHeartExplodeInterval: new EventInfo(Tab.Sounds), - SetHeartExplodeVolume: new EventInfo(Tab.Sounds), - SetMainWindow: new EventInfo(Tab.Windows), - SetOneshotWave: new EventInfo(Tab.Rows), - SetPlayStyle: new EventInfo(Tab.Actions), - SetRoomContentMode: new EventInfo(Tab.Rooms), - SetRoomPerspective: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), - SetRowXs: new EventInfo(Tab.Rows), - SetSpeed: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), - SetTheme: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - SetVFXPreset: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - SetVisible: new EventInfo(Tab.Decorations), - SetWindowContent: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent, "duration"), - ShakeScreen: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - ShakeScreenCustom: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - ShowDialogue: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - ShowHands: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - ShowRooms: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent, "duration"), - ShowStatusSign: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), - ShowSubdivisionsRows: new EventInfo(Tab.Actions), - SpinningRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration"), - Stutter: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - TagAction: new EventInfo(Tab.Actions), - TextExplosion: new EventInfo(Tab.Actions, EventAttriblte.RoomEvent), - Tile: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent, "duration"), - Tint: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent, "duration"), - TintRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent | EventAttriblte.RoomEvent, "duration"), - Unknown: new EventInfo(Tab.Unknown), - WindowResize: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent, "duration") -}; - // rdtkview.ts var lineHeight = 6; var charHeight = 8; @@ -680,63 +649,155 @@ var FilterData = class { function withState(color, active, enabled) { return (enabled ? color : new Color(4286874756)).withAlpha(active ? 192 : 91); } -async function createLayer(key, bound, color, style) { - const layer = document.createElement("div"); - layer.filterData = new FilterData(); - layer.updateFilter = () => { - layer.style.filter = layer.filterData.getFilter(); - }; +function createLayerFromBackground(key, bound, color, style, backgroundRepeat = false) { const info = slices.get(key); - layer.style.position = "absolute"; - layer.style.boxSizing = "content-box"; + if (!info) return []; if (info?.isNinePatch) { + const rectBound = bound ?? new Rect(0, 0, info.bounds.width, info.bounds.height); const center = info.center; - const width = bound?.width ?? info.bounds.width; - const height = bound?.height ?? info.bounds.height; - layer.style.left = `${(bound?.left ?? bound?.x ?? 0) * style.scale}px`; - layer.style.top = `${(bound?.top ?? bound?.y ?? 0) * style.scale}px`; - layer.style.borderStyle = "solid"; - layer.style.borderWidth = `${center.top * style.scale}px ${(info.bounds.width - center.right) * style.scale}px ${(info.bounds.height - center.bottom) * style.scale}px ${center.left * style.scale}px`; - layer.style.borderImageSource = `url(${await info.blobUrl()})`; - layer.style.borderImageSlice = `${center.top} ${info.bounds.width - center.right} ${info.bounds.height - center.bottom} ${center.left} fill`; - layer.style.borderImageWidth = `1`; - layer.style.borderImageOutset = `0`; - layer.style.borderImageRepeat = `repeat`; - layer.style.width = `${(width - center.left - (info.bounds.width - center.right)) * style.scale}px`; - layer.style.height = `${(height - center.top - (info.bounds.height - center.bottom)) * style.scale}px`; - } else { - if (bound instanceof Rect) { - layer.style.left = `${(bound.left - (info?.pivot.x ?? 0)) * style.scale}px`; - layer.style.top = `${(bound.top - (info?.pivot.y ?? 0)) * style.scale}px`; - layer.style.width = `${(bound.width ?? info?.bounds.width ?? 0) * style.scale}px`; - layer.style.height = `${(bound.height ?? info?.bounds.height ?? 0) * style.scale}px`; - if (info) { - layer.style.backgroundImage = `url(${await info.blobUrl()})`; + const left = rectBound.left; + const top = rectBound.top; + const width = rectBound.width; + const height = rectBound.height; + const infoLeft = info.bounds.left; + const infoTop = info.bounds.top; + const srcXs = [ + 0, + center.left, + center.right, + info.bounds.width + ]; + const srcYs = [ + 0, + center.top, + center.bottom, + info.bounds.height + ]; + const layers = []; + for (let y = 0; y < 3; y++) { + const srcTop = srcYs[y]; + const srcHeight = srcYs[y + 1] - srcYs[y]; + const dstTop = top + (y < 2 ? srcTop : height - (info.bounds.height - srcYs[y])); + const dstHeight = y === 1 ? height - center.top - (info.bounds.height - center.bottom) : srcHeight; + const heightScale = dstHeight / srcHeight; + for (let x = 0; x < 3; x++) { + const srcLeft = srcXs[x]; + const srcWidth = srcXs[x + 1] - srcXs[x]; + const dstLeft = left + (x < 2 ? srcLeft : width - (info.bounds.width - srcXs[x])); + const dstWidth = x === 1 ? width - center.left - (info.bounds.width - center.right) : srcWidth; + const widthScale = dstWidth / srcWidth; + if (backgroundRepeat && x === 1 && y === 1) { + for (let dstt = 0; dstt < dstHeight; dstt += srcHeight) { + const dsth = Math.min(srcHeight, dstHeight - dstt); + for (let dstl = 0; dstl < dstWidth; dstl += srcWidth) { + const dstw = Math.min(srcWidth, dstWidth - dstl); + const patchLayer = document.createElement("div"); + patchLayer.filterData = new FilterData(); + patchLayer.updateFilter = () => { + patchLayer.style.filter = patchLayer.filterData.getFilter(); + }; + patchLayer.style.position = "absolute"; + patchLayer.style.boxSizing = "content-box"; + patchLayer.style.backgroundClip = "content-box"; + patchLayer.style.backgroundImage = `url('${assetUrl}')`; + patchLayer.style.left = `${(dstLeft + dstl) * style.scale}px`; + patchLayer.style.top = `${(dstTop + dstt) * style.scale}px`; + patchLayer.style.width = `${dstw * style.scale}px`; + patchLayer.style.height = `${dsth * style.scale}px`; + patchLayer.style.backgroundPosition = `-${(infoLeft + srcLeft) * style.scale}px -${(infoTop + srcTop) * style.scale}px`; + patchLayer.style.backgroundSize = `${assetSize.width * style.scale}px ${assetSize.height * style.scale}px`; + layers.push(patchLayer); + } + } + } else { + const patchLayer = document.createElement("div"); + patchLayer.filterData = new FilterData(); + patchLayer.updateFilter = () => { + patchLayer.style.filter = patchLayer.filterData.getFilter(); + }; + patchLayer.style.position = "absolute"; + patchLayer.style.boxSizing = "content-box"; + patchLayer.style.backgroundClip = "content-box"; + patchLayer.style.backgroundImage = `url('${assetUrl}')`; + patchLayer.style.left = `${dstLeft * style.scale}px`; + patchLayer.style.top = `${dstTop * style.scale}px`; + patchLayer.style.width = `${dstWidth * style.scale}px`; + patchLayer.style.height = `${dstHeight * style.scale}px`; + patchLayer.style.backgroundPosition = `-${(infoLeft + srcLeft) * widthScale * style.scale}px -${(infoTop + srcTop) * heightScale * style.scale}px`; + patchLayer.style.backgroundSize = `${assetSize.width * widthScale * style.scale}px ${assetSize.height * heightScale * style.scale}px`; + layers.push(patchLayer); + } } - layer.style.backgroundSize = `${(bound.width ?? info?.bounds.width ?? 0) * style.scale}px ${(bound.height ?? info?.bounds.height ?? 0) * style.scale}px`; - } else { - layer.style.left = `${((bound?.x ?? 0) - (info?.pivot.x ?? 0)) * style.scale}px`; - layer.style.top = `${((bound?.y ?? 0) - (info?.pivot.y ?? 0)) * style.scale}px`; - layer.style.width = `${(info?.bounds.width ?? 0) * style.scale}px`; - layer.style.height = `${(info?.bounds.height ?? 0) * style.scale}px`; - if (info) { - layer.style.backgroundImage = `url(${await info.blobUrl()})`; - } - layer.style.backgroundSize = `${(info?.bounds.width ?? 0) * style.scale}px ${(info?.bounds.height ?? 0) * style.scale}px`; } - } - if (color && Color.White.equals(color) === false) { - layer.onColorChange = (color2) => { - if (!color2) { - return; - } - layer.filterData.color = color2; - layer.updateFilter(); - }; - layer.onColorChange(color); + if (color && Color.White.equals(color) === false) { + layers.forEach((layer) => { + layer.onColorChange = (color2) => { + if (!color2) { + return; + } + layer.filterData.color = color2; + layer.updateFilter(); + }; + layer.onColorChange(color); + }); + } else { + } + return layers; } else { + const pivotX = info.pivot.x ?? 0; + const pivotY = info.pivot.y ?? 0; + const layer = document.createElement("div"); + layer.filterData = new FilterData(); + layer.updateFilter = () => { + layer.style.filter = layer.filterData.getFilter(); + }; + layer.style.position = "absolute"; + layer.style.boxSizing = "content-box"; + layer.style.backgroundClip = "content-box"; + layer.style.backgroundImage = `url('${assetUrl}')`; + if (bound instanceof Rect) { + const left = bound.left; + const top = bound.top; + const width = bound.width; + const height = bound.height; + const infoLeft = info.bounds.left; + const infoTop = info.bounds.top; + layer.style.left = `${(left - pivotX) * style.scale}px`; + layer.style.top = `${(top - pivotY) * style.scale}px`; + layer.style.width = `${width * style.scale}px`; + layer.style.height = `${height * style.scale}px`; + layer.style.backgroundPosition = `-${infoLeft * style.scale}px -${infoTop * style.scale}px`; + layer.style.backgroundSize = `${assetSize.width * width * style.scale}px ${assetSize.height * height * style.scale}px`; + } else { + bound = bound ?? new Point(0, 0); + const left = bound.x; + const top = bound.y; + const width = info.bounds.width; + const height = info.bounds.height; + const infoLeft = info.bounds.left; + const infoTop = info.bounds.top; + layer.style.left = `${(left - pivotX) * style.scale}px`; + layer.style.top = `${(top - pivotY) * style.scale}px`; + layer.style.width = `${width * style.scale}px`; + layer.style.height = `${height * style.scale}px`; + layer.style.backgroundPosition = `-${infoLeft * style.scale}px -${infoTop * style.scale}px`; + layer.style.backgroundSize = `${assetSize.width * style.scale}px ${assetSize.height * style.scale}px`; + } + if (color && Color.White.equals(color) === false) { + layer.onColorChange = (color2) => { + if (!color2) { + return; + } + layer.filterData.color = color2; + layer.updateFilter(); + }; + layer.onColorChange(color); + } else { + } + return [ + layer + ]; } - return layer; } var colorMatrixIds = /* @__PURE__ */ new Map(); var colorMatrixCache = document.createElement("div"); @@ -778,7 +839,7 @@ function measureRDFontText(text) { } return len; } -async function createRDFontLayer(text, style, color) { +function createRDFontLayer(text, style, color) { const lineHead = new Point(0, -charHeight); const start = lineHead.clone(); const layer = document.createElement("div"); @@ -794,9 +855,9 @@ async function createRDFontLayer(text, style, color) { const charKey = `char_${charCode.toString(16).padStart(4, "0")}`; const charInfo = slices.get(charKey); if (charInfo) { - const charLayer = await createLayer(charKey, new Point(start.x, start.y), color, style); + const charLayer = createLayerFromBackground(charKey, new Point(start.x, start.y), color, style); start.x += charInfo.bounds.width * style.scale; - charLayers.push(charLayer); + charLayers.push(...charLayer); } } } @@ -813,21 +874,21 @@ async function createRDFontLayer(text, style, color) { function createBackLayer(size, color, style) { const outline = "event_outline"; const back = "event_back"; - const backLayer = createLayer(back, new Rect(1, 1, (size?.width ?? iconSize) - 2, (size?.height ?? iconSize) - 2), withState(color, style.active, style.enabled), style).then((layer) => { + const backLayer = createLayerFromBackground(back, new Rect(1, 1, (size?.width ?? iconSize) - 2, (size?.height ?? iconSize) - 2), withState(color, style.active, style.enabled), style); + backLayer.forEach((layer) => { if (layer.onColorChange) { layer.onStateChange = (style2) => layer.onColorChange(withState(color, style2.active, style2.enabled)); } - return layer; }); - const outlineLayer = createLayer(outline, size ? new Rect(size) : null, new Color(style.active ? 4294967295 : 4289243304), style).then((layer) => { + const outlineLayer = createLayerFromBackground(outline, size ? new Rect(size) : null, new Color(style.active ? 4294967295 : 4289243304), style); + outlineLayer.forEach((layer) => { if (layer.onColorChange) { layer.onStateChange = (style2) => layer.onColorChange(new Color(style2.active ? 4294967295 : 4289243304)); } - return layer; }); return [ - backLayer, - outlineLayer + ...backLayer, + ...outlineLayer ]; } function colorOf(tab) { @@ -890,7 +951,7 @@ function createHintLayer(hint, width, color) { }; return hintLayer; } -async function createElementEvent(obj, style) { +function createElementEvent(obj, style) { style = { ...new IconStyle(), ...style @@ -902,6 +963,7 @@ async function createElementEvent(obj, style) { } if (!slices.has(key0)) { if (!slices.has("event_Unknown")) { + console.log(slices); return null; } key0 = "event_Unknown"; @@ -926,6 +988,7 @@ async function createElementEvent(obj, style) { const evbarea = "event_beat_area"; const evbskip = "event_beat_skip"; const beatColor = new Color(4284539717); + let iconWidth = iconSize; const element = document.createElement("div"); element.eventStyle = { ...style @@ -943,25 +1006,27 @@ async function createElementEvent(obj, style) { syncoSwing: 0 }; const length = obj.length ?? 7; - const iconWidth = iconSize * (tick * (length - 1 - prexs.syncoSwing)); - const holdBar = hold > 0 ? createLayer(evbarea, new Rect(iconWidth, 0, iconSize * hold, iconSize), new Color(style.active ? 4291839731 : 4286462352), style).then((layer) => { + const iconWidth2 = iconSize * (tick * (length - 1 - prexs.syncoSwing)); + const holdBar = hold > 0 ? createLayerFromBackground(evbarea, new Rect(iconWidth2, 0, iconSize * hold, iconSize), new Color(style.active ? 4291839731 : 4286462352), style, true) : []; + holdBar.forEach((layer) => { layer.style.pointerEvents = "none"; return layer; - }) : null; - const backLayers2 = createBackLayer(new Size(iconWidth, iconSize), colorOf(obj.tab ?? evinfo.defaultTab), style); + }); + const backLayers2 = createBackLayer(new Size(iconWidth2, iconSize), colorOf(obj.tab ?? evinfo.defaultTab), style); const pulses = []; for (let i = 0; i < length - 1; i++) { - const pulseLayer = createLayer(pulse, new Point(iconSize * (tick * (i + i % 2 * (1 - swing) - (i <= prexs.syncoBeat ? 0 : prexs.syncoSwing))), 0), null, style).then((layer) => { + const pulseLayer = createLayerFromBackground(pulse, new Point(iconSize * (tick * (i + i % 2 * (1 - swing) - (i <= prexs.syncoBeat ? 0 : prexs.syncoSwing))), 0), null, style); + pulseLayer.forEach((layer) => { layerHoverInit(layer); return layer; }); - pulses.push(pulseLayer); + pulses.push(...pulseLayer); } - const hitLayer = createLayer(hit, new Point(iconSize * (tick * (length - 1 - (prexs.syncoSwing ?? 0))) - 1, 0), null, style); - layersToAdd.push(holdBar); + const hitLayer = createLayerFromBackground(hit, new Point(iconSize * (tick * (length - 1 - (prexs.syncoSwing ?? 0))) - 1, 0), null, style); + layersToAdd.push(...holdBar); layersToAdd.push(...backLayers2); layersToAdd.push(...pulses); - layersToAdd.push(hitLayer); + layersToAdd.push(...hitLayer); } break; case EventType.AddOneshotBeat: @@ -979,52 +1044,60 @@ async function createElementEvent(obj, style) { const off = interval - tick; const backLayers2 = createBackLayer(new Size(eventWidth, iconSize), colorOf(obj.tab ?? evinfo.defaultTab), style); const holdWidth = hold ? iconSize * (interval - tick - delay) : 0; - const holdLayer = hold && holdWidth - subdivWidth > 0 ? createLayer(evbarea, new Rect(eventWidth + subdivWidth, 0, holdWidth - subdivWidth, iconSize), new Color(style.enabled ? 4291839731 : 4285493103), style).then((layer) => { + const holdLayer = hold && holdWidth - subdivWidth > 0 ? createLayerFromBackground(evbarea, new Rect(eventWidth + subdivWidth, 0, holdWidth - subdivWidth, iconSize), new Color(style.enabled ? 4291839731 : 4285493103), style, true) : []; + holdLayer.forEach((layer) => { layer.style.pointerEvents = "none"; return layer; - }) : null; - const subdivLayer = subdiv > 1 ? createLayer(evbarea, new Rect(eventWidth, 0, subdivWidth, iconSize), new Color(style.enabled ? 4279480353 : 4285493103), style).then((layer) => { + }); + const subdivLayer = subdiv > 1 ? createLayerFromBackground(evbarea, new Rect(eventWidth, 0, subdivWidth, iconSize), new Color(style.enabled ? 4279480353 : 4285493103), style, true) : []; + subdivLayer.forEach((layer) => { layer.style.pointerEvents = "none"; return layer; - }) : null; - const skipshotLayer = skip ? createLayer(evbarea, new Rect(eventWidth + Math.max(subdivWidth, holdWidth), 0, iconSize * (interval - delay) - Math.max(subdivWidth, holdWidth), iconSize), new Color(style.enabled ? 4291115835 : 4285493103), style).then((layer) => { + }); + const skipshotLayer = skip ? createLayerFromBackground(evbarea, new Rect(eventWidth + Math.max(subdivWidth, holdWidth), 0, iconSize * (interval - delay) - Math.max(subdivWidth, holdWidth), iconSize), new Color(style.enabled ? 4291115835 : 4285493103), style, true) : []; + skipshotLayer.forEach((layer) => { layer.style.pointerEvents = "none"; return layer; - }) : null; - const skipHitLayer = skip ? createLayer(evbskip, new Point(eventWidth + iconSize * (interval - delay) - 1, 0), null, style).then((layer) => { + }); + const skipHitLayer = skip ? createLayerFromBackground(evbskip, new Point(eventWidth + iconSize * (interval - delay) - 1, 0), null, style) : []; + skipHitLayer.forEach((layer) => { layer.style.pointerEvents = "none"; return layer; - }) : null; + }); const pulses = []; const crossLayers = []; const posx = -off * iconSize; const hittype = mode === "Freezeshot" ? hitf : mode === "Burnshot" ? hitb : null; for (let l = 0; l <= loop; l++) { for (let i = 0; i < subdiv; i++) { - const pulseLayer = createLayer(pulse, new Point(iconSize * (l * interval + i * tick / subdiv), 0), null, style).then((layer) => { + const pulseLayer = createLayerFromBackground(pulse, new Point(iconSize * (l * interval + i * tick / subdiv), 0), null, style); + pulseLayer.forEach((layer) => { layerHoverInit(layer); return layer; }); - pulses.push(pulseLayer); + pulses.push(...pulseLayer); } for (let i = 0; i < subdiv; i++) { - const hitLayer2 = createLayer(hit, new Point(iconSize * (l * interval + delay + tick + i * tick / subdiv) - 1, 0), null, style); - pulses.push(hitLayer2); + const hitLayer2 = createLayerFromBackground(hit, new Point(iconSize * (l * interval + delay + tick + i * tick / subdiv) - 1, 0), null, style); + pulses.push(...hitLayer2); } - const crossLayer1 = mode || hold ? createLayer(beatcross, new Point(iconSize * l * interval + posx - 1, 0), null, style).then((layer) => { + const crossLayer1 = mode || hold ? createLayerFromBackground(beatcross, new Point(iconSize * l * interval + posx - 1, 0), null, style) : []; + crossLayer1.forEach((layer) => { layerHoverInit(layer); return layer; - }) : null; - const crossLayer2 = mode ? createLayer(beatcross, new Point(iconSize * (l - (mode === "Freezeshot" ? 0 : 1)) * interval - 1, 0), null, style).then((layer) => { + }); + const crossLayer2 = mode ? createLayerFromBackground(beatcross, new Point(iconSize * (l - (mode === "Freezeshot" ? 0 : 1)) * interval - 1, 0), null, style) : []; + crossLayer2.forEach((layer) => { layerHoverInit(layer); return layer; - }) : null; - const hitLayer = hittype ? createLayer(hittype, new Point(iconSize * (l * interval + tick) - 1, 0), null, style) : null; - crossLayers.push(crossLayer1); - crossLayers.push(crossLayer2); - pulses.push(hitLayer); + }); + const hitLayer = hittype ? createLayerFromBackground(hittype, new Point(iconSize * (l * interval + tick) - 1, 0), null, style) : []; + crossLayers.push(...crossLayer1); + crossLayers.push(...crossLayer2); + pulses.push(...hitLayer); } - const loopLayer = createLayer("event_beat_loop", new Point(eventWidth, 0), null, style).then((loopLayer2) => { + const loopLayer = createLayerFromBackground("event_beat_loop", new Point(eventWidth, 0), null, style); + loopLayer.forEach((loopLayer2) => { loopLayer2.style.opacity = "0"; loopLayer2.style.zIndex = "5"; loopLayer2.onStateChange = (style2) => { @@ -1037,62 +1110,62 @@ async function createElementEvent(obj, style) { return loopLayer2; }); layersToAdd.push(...backLayers2); - layersToAdd.push(holdLayer); - layersToAdd.push(subdivLayer); - layersToAdd.push(skipshotLayer); - layersToAdd.push(skipHitLayer); + layersToAdd.push(...holdLayer); + layersToAdd.push(...subdivLayer); + layersToAdd.push(...skipshotLayer); + layersToAdd.push(...skipHitLayer); layersToAdd.push(...pulses); - layersToAdd.push(loopLayer); + layersToAdd.push(...loopLayer); layersToAdd.push(...crossLayers); } break; case EventType.AddFreeTimeBeat: { const hold = obj.hold ?? 0; - const holdLayer = hold > 0 ? createLayer(evbarea, new Rect(slcinfo.bounds.width, 0, iconSize * hold - slcinfo.bounds.width, iconSize), new Color(style.active ? 4291839731 : 4286462352), style).then((layer) => { + const holdLayer = hold > 0 ? createLayerFromBackground(evbarea, new Rect(slcinfo.bounds.width, 0, iconSize * hold - slcinfo.bounds.width, iconSize), new Color(style.active ? 4291839731 : 4286462352), style, true) : []; + holdLayer.forEach((layer) => { layer.style.pointerEvents = "none"; return layer; - }) : null; - const backLayers2 = createBackLayer(new Size(slcinfo.bounds.width, iconSize), beatColor, style); - const hitLayer = obj.pulse === 6 ? createLayer(hit, new Point(0, 0), null, style) : null; - const textLayer = createRDFontLayer(((obj.pulse ?? 0) + 1).toString(), style, null).then((textLayer2) => { - textLayer2.style.left = `${1.5 * style.scale}px`; - textLayer2.style.top = `${10 * style.scale}px`; - return textLayer2; }); - layersToAdd.push(holdLayer); + const backLayers2 = createBackLayer(new Size(slcinfo.bounds.width, iconSize), beatColor, style); + const hitLayer = obj.pulse === 6 ? createLayerFromBackground(hit, new Point(0, 0), null, style) : []; + const textLayer = createRDFontLayer(((obj.pulse ?? 0) + 1).toString(), style, null); + textLayer.style.left = `${1.5 * style.scale}px`; + textLayer.style.top = `${10 * style.scale}px`; + layersToAdd.push(...holdLayer); layersToAdd.push(...backLayers2); - layersToAdd.push(hitLayer); + layersToAdd.push(...hitLayer); layersToAdd.push(textLayer); } break; case EventType.Comment: { const backLayers2 = createBackLayer(slcinfo.bounds.size, new Color(obj.color ?? "7d7d7d"), style); - const iconLayer = createLayer(key, null, null, style); + const iconLayer = createLayerFromBackground(key, null, null, style); layersToAdd.push(...backLayers2); - layersToAdd.push(iconLayer); + layersToAdd.push(...iconLayer); } break; case EventType.DesktopColor: { const backLayers2 = createBackLayer(slcinfo.bounds.size, colorOf(obj.tab ?? evinfo.defaultTab), style); - const iconColorLayer = createLayer(`${key}_0`, new Point(0, iconSize), new Color(obj.endColor ?? "ffffff"), style); - const iconLayer = createLayer(`${key}_1`, new Point(0, iconSize), null, style); + const iconColorLayer = createLayerFromBackground(`${key}_0`, new Point(0, iconSize), new Color(obj.endColor ?? "ffffff"), style); + const iconLayer = createLayerFromBackground(`${key}_1`, new Point(0, iconSize), null, style); layersToAdd.push(...backLayers2); - layersToAdd.push(iconColorLayer); - layersToAdd.push(iconLayer); + layersToAdd.push(...iconColorLayer); + layersToAdd.push(...iconLayer); } break; case EventType.PulseFreeTimeBeat: { const hold = obj.hold ?? 0; - const holdLayer = hold > 0 ? createLayer(evbarea, new Rect(slcinfo.bounds.width, 0, iconSize * hold - slcinfo.bounds.width, slcinfo.bounds.height), new Color(style.active ? 4291839731 : 4286462352), style).then((layer) => { + const holdLayer = hold > 0 ? createLayerFromBackground(evbarea, new Rect(slcinfo.bounds.width, 0, iconSize * hold - slcinfo.bounds.width, slcinfo.bounds.height), new Color(style.active ? 4291839731 : 4286462352), style, true) : []; + holdLayer.forEach((layer) => { layer.style.pointerEvents = "none"; return layer; - }) : null; + }); const backLayers2 = createBackLayer(new Size(slcinfo.bounds.width, slcinfo.bounds.height), beatColor, style); - const hitLayer = obj.pulse === 6 ? createLayer(hit, new Point(0, 0), null, style) : null; + const hitLayer = obj.pulse === 6 ? createLayerFromBackground(hit, new Point(0, 0), null, style) : []; let text = ""; switch (obj.action) { case "Custom": @@ -1108,14 +1181,12 @@ async function createElementEvent(obj, style) { text = "x"; break; } - const textLayer = createRDFontLayer(text, style, null).then((textLayer2) => { - textLayer2.style.left = `${1.5 * style.scale}px`; - textLayer2.style.top = `${10 * style.scale}px`; - return textLayer2; - }); - layersToAdd.push(holdLayer); + const textLayer = createRDFontLayer(text, style, null); + textLayer.style.left = `${1.5 * style.scale}px`; + textLayer.style.top = `${10 * style.scale}px`; + layersToAdd.push(...holdLayer); layersToAdd.push(...backLayers2); - layersToAdd.push(hitLayer); + layersToAdd.push(...hitLayer); layersToAdd.push(textLayer); } break; @@ -1132,8 +1203,8 @@ async function createElementEvent(obj, style) { ]; for (let i = 0; i < order.length; i++) { { - const orderLayer = createLayer(`${key}_${order[i]}`, new Point(0, i * iconSize), null, style); - orderLayers.push(orderLayer); + const orderLayer = createLayerFromBackground(`${key}_${order[i]}`, new Point(0, i * iconSize), null, style); + orderLayers.push(...orderLayer); } } layersToAdd.push(...backLayers2); @@ -1144,6 +1215,7 @@ async function createElementEvent(obj, style) { { const wordInfo = WordInfos[obj.phraseToSay ?? SayReadyGetSetGoWords.JustSayGo]; const len = wordInfo.length * (obj.tick ?? 0) + 1; + iconWidth = len * iconSize; const stringToJoin = wordInfo.phrase.split(" "); const stringToDraw = [ stringToJoin[0] @@ -1171,11 +1243,9 @@ async function createElementEvent(obj, style) { const wordLayer = createRDFontLayer(line, { ...style, scale: style.scale / 2 - }, null).then((wordLayer2) => { - wordLayer2.style.left = `${p.x * style.scale}px`; - wordLayer2.style.top = `${p.y * style.scale}px`; - return wordLayer2; - }); + }, null); + wordLayer.style.left = `${p.x * style.scale}px`; + wordLayer.style.top = `${p.y * style.scale}px`; wordLayers.push(wordLayer); } layersToAdd.push(...backLayers2); @@ -1193,14 +1263,14 @@ async function createElementEvent(obj, style) { const patternLayers = []; const backLayers2 = createBackLayer(new Size(slcinfo.bounds.width, slcinfo.bounds.height), colorOf(obj.tab ?? evinfo.defaultTab), style); for (let p of obj.pattern ?? "------") { - const beatxLayer = createLayer(p === "x" ? beatx : beatline, new Rect(left, top, width, iconBounds.height * s), null, style); - patternLayers.push(beatxLayer); + const beatxLayer = createLayerFromBackground(p === "x" ? beatx : beatline, new Rect(left, top, width, iconBounds.height * s), null, style); + patternLayers.push(...beatxLayer); left += width; } - const syncoBeatLayer = syncoBeat >= 0 ? createLayer(beatsynco, new Rect(width * syncoBeat, top, width, iconBounds.height * s), null, style) : null; + const syncoBeatLayer = syncoBeat >= 0 ? createLayerFromBackground(beatsynco, new Rect(width * syncoBeat, top, width, iconBounds.height * s), null, style) : []; layersToAdd.push(...backLayers2); layersToAdd.push(...patternLayers); - layersToAdd.push(syncoBeatLayer); + layersToAdd.push(...syncoBeatLayer); } break; case EventType.ShowRooms: @@ -1208,11 +1278,11 @@ async function createElementEvent(obj, style) { const backLayers2 = createBackLayer(new Size(iconSize, iconSize * 4), colorOf(obj.tab ?? evinfo.defaultTab), style); const roomLayers = []; for (let i = 0; i < 4; i++) { - const roomLayer = createLayer(`${key}_${(obj.rooms ?? []).indexOf(i) >= 0 ? "1" : "0"}`, new Point(0, i * iconSize * style.scale), null, { + const roomLayer = createLayerFromBackground(`${key}_${(obj.rooms ?? []).indexOf(i) >= 0 ? "1" : "0"}`, new Point(0, i * iconSize * style.scale), null, { ...style, scale: style.scale / 2 }); - roomLayers.push(roomLayer); + roomLayers.push(...roomLayer); } layersToAdd.push(...backLayers2); layersToAdd.push(...roomLayers); @@ -1223,30 +1293,39 @@ async function createElementEvent(obj, style) { layersToAdd.push(...backLayers); switch (evttype) { case EventType.CustomFlash: - const iconLayer = createLayer(key, null, null, style); - const startColorLayer = createLayer(`${key}_0`, null, new Color(obj.startColor ?? "000000").withAlpha((obj.startOpacity ?? 0) * 255), style); - const endColorLayer = createLayer(`${key}_1`, null, new Color(obj.endColor ?? "000000").withAlpha((obj.endOpacity ?? 0) * 255), style); - layersToAdd.push(iconLayer); - layersToAdd.push(startColorLayer); - layersToAdd.push(endColorLayer); + const iconLayer = createLayerFromBackground(key, null, null, style); + const startColorLayer = createLayerFromBackground(`${key}_0`, null, new Color(obj.startColor ?? "000000").withAlpha((obj.startOpacity ?? 0) * 255), style); + const endColorLayer = createLayerFromBackground(`${key}_1`, null, new Color(obj.endColor ?? "000000").withAlpha((obj.endOpacity ?? 0) * 255), style); + layersToAdd.push(...iconLayer); + layersToAdd.push(...startColorLayer); + layersToAdd.push(...endColorLayer); break; case EventType.FlipScreen: { const flip = (obj.flipX ? 1 : 0) | (obj.flipY ? 2 : 0); - const iconLayer2 = createLayer(flip === 0 ? `${key}_0` : `${key}_${flip - 1}`, null, null, style); - layersToAdd.push(iconLayer2); + const iconLayer2 = createLayerFromBackground(flip === 0 ? `${key}_0` : `${key}_${flip - 1}`, null, null, style); + layersToAdd.push(...iconLayer2); } break; case EventType.FloatingText: { - const backColorLayer = createLayer(`${key}_0`, null, Color.FromRgba(obj.color ?? "FFFFFFFF"), style); - const foreColorLayer = createLayer(`${key}_1`, null, Color.FromRgba(obj.outlineColor ?? "FFFFFFFF"), style); - layersToAdd.push(backColorLayer); - layersToAdd.push(foreColorLayer); + const backColorLayer = createLayerFromBackground(`${key}_0`, null, Color.FromRgba(obj.color ?? "FFFFFFFF"), style); + const foreColorLayer = createLayerFromBackground(`${key}_1`, null, Color.FromRgba(obj.outlineColor ?? "FFFFFFFF"), style); + layersToAdd.push(...backColorLayer); + layersToAdd.push(...foreColorLayer); } break; case EventType.MoveRoom: { + obj.scale ??= [ + null, + null + ]; + const hasPivot = obj.pivot !== void 0; + obj.pivot ??= [ + null, + null + ]; const degree = obj.angle ?? 0; const radius = -degree * Math.PI / 180; let width = (obj.scale ? obj.scale[0] ?? 0 : 100) / 100; @@ -1257,23 +1336,26 @@ async function createElementEvent(obj, style) { const uniform = Math.sqrt(width * width + height * height); width /= uniform; height /= uniform; - const roomLayer = createLayer(key, new Rect(iconSize / 2, iconSize / 2, iconSize * width, iconSize * height), null, style).then((roomLayer2) => { + const roomLayer = createLayerFromBackground(key, new Rect(iconSize / 2, iconSize / 2, iconSize * width, iconSize * height), null, style); + roomLayer.forEach((roomLayer2) => { roomLayer2.style.transform = `translate(-50%, -50%) rotate(${-degree}deg)`; return roomLayer2; }); - let pivotx = width * (1 - pleft * 2); - let pivoty = height * (1 - ptop * 2); - const widthrotated = pivotx * Math.cos(radius) + pivoty * Math.sin(radius); - const heightrotated = -pivotx * Math.sin(radius) + pivoty * Math.cos(radius); - const pointLayer = document.createElement("div"); - pointLayer.style.position = "absolute"; - pointLayer.style.width = `${style.scale}px`; - pointLayer.style.height = `${style.scale}px`; - pointLayer.style.left = `${iconSize * (1 - widthrotated) * style.scale / 2}px`; - pointLayer.style.top = `${iconSize * (1 + heightrotated) * style.scale / 2}px`; - pointLayer.style.backgroundColor = "#FF0000"; - layersToAdd.push(roomLayer); - layersToAdd.push(Promise.resolve(pointLayer)); + layersToAdd.push(...roomLayer); + if (hasPivot) { + let pivotx = width * (1 - pleft * 2); + let pivoty = height * (1 - ptop * 2); + const widthrotated = pivotx * Math.cos(radius) + pivoty * Math.sin(radius); + const heightrotated = -pivotx * Math.sin(radius) + pivoty * Math.cos(radius); + const pointLayer = document.createElement("div"); + pointLayer.style.position = "absolute"; + pointLayer.style.width = `${style.scale}px`; + pointLayer.style.height = `${style.scale}px`; + pointLayer.style.left = `${iconSize * (1 - widthrotated) * style.scale / 2}px`; + pointLayer.style.top = `${iconSize * (1 + heightrotated) * style.scale / 2}px`; + pointLayer.style.backgroundColor = "#FF0000"; + layersToAdd.push(pointLayer); + } } break; case EventType.PaintHands: @@ -1281,75 +1363,73 @@ async function createElementEvent(obj, style) { case EventType.TintRows: { const border = obj.border; - const backColorLayer = createLayer(key, null, Color.FromRgba(obj.tintColor ?? "FFFFFFFF"), style); - const foreColorLayer = border ? createLayer(border === "Outline" ? `${key}_0` : border === "Glow" ? `${key}_1` : "", null, Color.FromRgba(obj.borderColor ?? "FFFFFFFF"), style) : null; - layersToAdd.push(backColorLayer); - layersToAdd.push(foreColorLayer); + const backColorLayer = createLayerFromBackground(key, null, Color.FromRgba(obj.tintColor ?? "FFFFFFFF"), style); + const foreColorLayer = border ? createLayerFromBackground(border === "Outline" ? `${key}_0` : border === "Glow" ? `${key}_1` : "", null, Color.FromRgba(obj.borderColor ?? "FFFFFFFF"), style) : []; + layersToAdd.push(...backColorLayer); + layersToAdd.push(...foreColorLayer); } break; case EventType.SetBackgroundColor: { const backType = obj.backgroundType ?? "Color"; - const iconLayer2 = createLayer(key, null, null, style); + const iconLayer2 = createLayerFromBackground(key, null, null, style); const images = obj.image ?? []; const imagePath = images.length > 0 ? images[0] : ""; const contentInfo = slices.get(`${key}_1`); - const colorLayer = createLayer(`${key}_0`, null, Color.FromRgba((backType === "Color" ? obj.color : null) ?? "FFFFFF"), style); - const contentLayer = backType === "Image" ? createLayer("", contentInfo?.bounds ? new Rect(contentInfo?.bounds.size) : null, null, style).then((contentLayer2) => { + const colorLayer = createLayerFromBackground(`${key}_0`, null, Color.FromRgba((backType === "Color" ? obj.color : null) ?? "FFFFFF"), style); + const contentLayer = backType === "Image" ? createLayerFromBackground("", contentInfo?.bounds ? new Rect(contentInfo?.bounds.size) : null, null, style) : []; + contentLayer.forEach((contentLayer2) => { if (backType === "Image" && contentLayer2) { contentLayer2.style.backgroundImage = `url(${imagePath})`; contentLayer2.style.left = `${-(contentInfo?.pivot.x ?? 0) * style.scale}px`; contentLayer2.style.top = `${-(contentInfo?.pivot.y ?? 0) * style.scale}px`; } return contentLayer2; - }) : null; - layersToAdd.push(iconLayer2); - layersToAdd.push(colorLayer); - layersToAdd.push(contentLayer); + }); + layersToAdd.push(...iconLayer2); + layersToAdd.push(...colorLayer); + layersToAdd.push(...contentLayer); } break; case EventType.SetCrotchetsPerBar: { const cpb = obj.crotchetsPerBar ?? 0; - const iconLayer2 = createLayer(key, null, null, style); - const cpbLayer = createRDFontLayer(cpb > 9 ? "-" : cpb.toString(), style, Color.Black).then((cpbLayer2) => { - cpbLayer2.style.left = `${2 * style.scale}px`; - cpbLayer2.style.top = `${9 * style.scale}px`; - return cpbLayer2; - }); - const bLayer = createRDFontLayer("4", style, Color.Black).then((bLayer2) => { - bLayer2.style.left = `${8 * style.scale}px`; - bLayer2.style.top = `${14 * style.scale}px`; - return bLayer2; - }); - layersToAdd.push(iconLayer2); + const iconLayer2 = createLayerFromBackground(key, null, null, style); + const cpbLayer = createRDFontLayer(cpb > 9 ? "-" : cpb.toString(), style, Color.Black); + cpbLayer.style.left = `${2 * style.scale}px`; + cpbLayer.style.top = `${9 * style.scale}px`; + const bLayer = createRDFontLayer("4", style, Color.Black); + bLayer.style.left = `${8 * style.scale}px`; + bLayer.style.top = `${14 * style.scale}px`; + layersToAdd.push(...iconLayer2); layersToAdd.push(cpbLayer); layersToAdd.push(bLayer); } break; case EventType.SetForeground: { - const iconLayer2 = createLayer(key, null, null, style); + const iconLayer2 = createLayerFromBackground(key, null, null, style); const images = obj.image ?? []; const imagePath = images.length > 0 ? images[0] : ""; const contentInfo = slices.get(`${key}_1`); - const colorLayer = imagePath ? createLayer(`${key}_0`, null, Color.Black, style) : null; - const contentLayer = imagePath ? createLayer("", contentInfo?.bounds ? new Rect(contentInfo?.bounds.size) : null, null, style).then((contentLayer2) => { + const colorLayer = imagePath ? createLayerFromBackground(`${key}_0`, null, Color.Black, style) : []; + const contentLayer = imagePath ? createLayerFromBackground("", contentInfo?.bounds ? new Rect(contentInfo?.bounds.size) : null, null, style) : []; + contentLayer.forEach((contentLayer2) => { if (contentLayer2) { contentLayer2.style.backgroundImage = `url(${imagePath})`; contentLayer2.style.left = `${-(contentInfo?.pivot.x ?? 0) * style.scale}px`; contentLayer2.style.top = `${-(contentInfo?.pivot.y ?? 0) * style.scale}px`; } return contentLayer2; - }) : null; - layersToAdd.push(iconLayer2); - layersToAdd.push(colorLayer); - layersToAdd.push(contentLayer); + }); + layersToAdd.push(...iconLayer2); + layersToAdd.push(...colorLayer); + layersToAdd.push(...contentLayer); } break; default: - const layer = createLayer(hasType ? key : "event_Unknown", null, null, style); - layersToAdd.push(layer); + const layer = createLayerFromBackground(hasType ? key : "event_Unknown", null, null, style); + layersToAdd.push(...layer); break; } break; @@ -1357,12 +1437,13 @@ async function createElementEvent(obj, style) { if (evinfo.isDurationEvent) { const duration = obj[evinfo.durationKey] ?? 0; const durWidth = iconSize * duration; - const durationLayer = durWidth > slcinfo.bounds.width ? createLayer(evbarea, new Rect(slcinfo.bounds.width, 0, durWidth - slcinfo.bounds.width, slcinfo.bounds.height), colorOf(obj.tab ?? evinfo.defaultTab), style).then((layer) => { + const durationLayer = durWidth > slcinfo.bounds.width ? createLayerFromBackground(evbarea, new Rect(slcinfo.bounds.width, 0, durWidth - slcinfo.bounds.width, slcinfo.bounds.height), colorOf(obj.tab ?? evinfo.defaultTab), style, true) : []; + durationLayer.forEach((layer) => { layer.style.pointerEvents = "none"; layerHoverInit(layer); return layer; - }) : null; - layersToAdd.push(durationLayer); + }); + layersToAdd.push(...durationLayer); } const rooms = obj.rooms ?? []; const roomEnabled = new Color(4292392977); @@ -1370,32 +1451,27 @@ async function createElementEvent(obj, style) { if (evinfo.isRoomEvent) { const roomLayers = []; for (let i = 0; i < 4; i++) { - const roomLayer = createLayer(`room_${i}`, new Point(iconSize, 0), rooms.indexOf(i) > -1 ? roomEnabled : roomDisabled, style).then((roomLayer2) => { - if (roomLayer2) { - layerHoverInit(roomLayer2); - } - return roomLayer2; - }); - roomLayers.push(roomLayer); + const roomLayer = createLayerFromBackground(`room_${i}`, new Point(iconWidth, 0), rooms.indexOf(i) > -1 ? roomEnabled : roomDisabled, style); + roomLayers.push(...roomLayer); } - const roomTopLayer = rooms.indexOf(4) > -1 ? createLayer(`room_top`, new Point(iconSize, 0), roomEnabled, style).then((roomTopLayer2) => { - if (roomTopLayer2) { - layerHoverInit(roomTopLayer2); + const roomTopLayer = rooms.indexOf(4) > -1 ? createLayerFromBackground(`room_top`, new Point(iconWidth, 0), roomEnabled, style) : []; + roomLayers.push(...roomTopLayer); + roomLayers.forEach((roomLayer) => { + if (roomLayer) { + layerHoverInit(roomLayer); } - return roomTopLayer2; - }) : null; - roomLayers.push(roomTopLayer); + }); layersToAdd.push(...roomLayers); } const condition = obj.if ?? ""; if (condition.length > 0) { const positive = /(? layer?.then((layer2) => { - layer2.filterData.hue = hsb[0]; - layer2.filterData.saturation = hsb[1]; - layer2.filterData.brightness = hsb[2]; - })); + layersToAdd.forEach((layer) => { + layer.filterData.hue = hsb[0]; + layer.filterData.saturation = hsb[1]; + layer.filterData.brightness = hsb[2]; + }); } - layersToAdd.forEach((layer) => layer?.then((layer2) => { - layer2.updateFilter(); - })); + layersToAdd.forEach((layer) => { + layer.updateFilter(); + }); } element.onStateChange = (style2) => { style2 = { ...style2 }; - layersToAdd.forEach((layer) => layer?.then((layer2) => { - if (layer2.onStateChange) { - layer2.onStateChange(style2); + layersToAdd.forEach((layer) => { + if (layer.onStateChange) { + layer.onStateChange(style2); } - })); + }); }; element.moveTo = function(x, y) { this.style.left = `${x}px`; this.style.top = `${y}px`; }; - for await (const layer of layersToAdd) { + for (const layer of layersToAdd) { if (layer) { element.appendChild(layer); } diff --git a/script/rdtkview_render.js b/script/rdtkview_render.js new file mode 100644 index 0000000..8e0addc --- /dev/null +++ b/script/rdtkview_render.js @@ -0,0 +1,82 @@ +import { createElementEvent } from "./rdtkview.js"; +export function render(data, width, height, scale = 2.0) { + const canvas = document.createElement("div"); + let objs = []; + try { + objs = JSON.parse(`[${data}]`); + canvas.innerHTML = ""; + } catch (e) { + canvas.innerHTML = + `
JSON解析错误:${e.message}
`; + return canvas; + } + const eventStyle = { "scale": scale, "showDuration": false }; + const elems = []; + for (let obj of objs) { + const style = { ...eventStyle, enabled: obj.active ?? true }; + const elem = createElementEvent(obj, style); + console.log(obj, elem); + if (!elem) continue; + elem.eventStyle = style; + elem.style.position = "absolute"; + elem.style.left = `${ + ((((obj.bar ?? 1) - 1) * 8) + (obj.beat ?? 1) - 1) * 14 * + scale + }px`; + elem.style.top = `${(obj.y ?? obj.row ?? 0) * 14 * scale}px`; + elem.addEventListener("mousedown", (event) => { + const eStyle = elem.eventStyle; + eStyle.active = true; + elem.onStateChange(eStyle); + }); + elem.addEventListener("mouseover", (event) => { + const eStyle = elem.eventStyle; + eStyle.hover = true; + elem.onStateChange(eStyle); + }); + elem.addEventListener("mouseout", (event) => { + const eStyle = elem.eventStyle; + eStyle.hover = false; + eStyle.active = false; + elem.onStateChange(eStyle); + }); + elem.addEventListener("mouseup", (event) => { + const eStyle = elem.eventStyle; + eStyle.active = false; + elem.onStateChange(eStyle); + }); + elems.push(elem); + } + canvas.style.position = "relative"; + canvas.style.width = `${width * 14 * scale}px`; + canvas.style.height = `${height * 14 * scale}px`; + elems.forEach((elem) => { + canvas.appendChild(elem); + }); + return canvas; +} + +window.$docsify.plugins = [].concat(window.$docsify.plugins, (hook) => { + hook.doneEach(() => { + console.log("hello"); + const pres = document.querySelectorAll("pre"); + pres.forEach((codeBlock) => { + const lang = codeBlock.getAttribute("data-lang") || ""; + console.log(codeBlock, lang); + if (lang.startsWith("rdtkview")) { + const code = codeBlock.querySelector("code").innerText || ""; + const args = lang.slice(8).trim().split(" "); + const width = parseInt(args[0]) || 8; + const height = parseInt(args[1]) || 4; + const scale = parseFloat(args[2]) || 2.0; + const result = render(code, width, height, scale); + const parent = document.createElement("div"); + parent.style.width = 100 + "%"; + parent.style.display = "flex"; + parent.style.justifyContent = "center"; + parent.appendChild(result); + codeBlock.replaceWith(parent); + } + }); + }); +}); diff --git a/script/special.js b/script/special.js index 536258a..5e8ce8d 100644 --- a/script/special.js +++ b/script/special.js @@ -366,12 +366,12 @@ function rdview2() { return elem; }); elemPromises.push(elem); - Promise.all(elemPromises).then((elems) => { - elems.forEach((elem) => { - rdcanvas.appendChild(elem); - }); - }); } + Promise.all(elemPromises).then((elems) => { + elems.forEach((elem) => { + rdcanvas.appendChild(elem); + }); + }); rdcanvas.style.position = "relative"; rdcanvas.style.height = `${maxy + 4 * 14 * eventStyle.scale}px`; } From a14b4436f58b9f7c75004e1e557ff7b43cc47d6a Mon Sep 17 00:00:00 2001 From: OLDREDSTONE Date: Fri, 16 Jan 2026 20:14:42 +0800 Subject: [PATCH 3/8] =?UTF-8?q?[RDView]=20=E5=95=8A=E8=8D=89=E6=88=91=20de?= =?UTF-8?q?gug=20=E6=80=8E=E4=B9=88=E8=BF=98=E5=9C=A8=E9=87=8C=E9=9D=A2?= =?UTF-8?q?=EF=BC=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/changelog.md | 3 +++ script/rdtkview_render.js | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/changelog.md b/pages/changelog.md index a3038ea..ceb0c08 100644 --- a/pages/changelog.md +++ b/pages/changelog.md @@ -1,5 +1,8 @@ # 更新信息 +#### 2026-01-16 +- RDTKView(~~RDView2~~) 已完成部署 + #### 2026-01-14 - 制作人员表增加了 - RDView 对正式版编辑器新特性的部分适配 diff --git a/script/rdtkview_render.js b/script/rdtkview_render.js index 8e0addc..5b0c074 100644 --- a/script/rdtkview_render.js +++ b/script/rdtkview_render.js @@ -15,7 +15,6 @@ export function render(data, width, height, scale = 2.0) { for (let obj of objs) { const style = { ...eventStyle, enabled: obj.active ?? true }; const elem = createElementEvent(obj, style); - console.log(obj, elem); if (!elem) continue; elem.eventStyle = style; elem.style.position = "absolute"; @@ -58,11 +57,9 @@ export function render(data, width, height, scale = 2.0) { window.$docsify.plugins = [].concat(window.$docsify.plugins, (hook) => { hook.doneEach(() => { - console.log("hello"); const pres = document.querySelectorAll("pre"); pres.forEach((codeBlock) => { const lang = codeBlock.getAttribute("data-lang") || ""; - console.log(codeBlock, lang); if (lang.startsWith("rdtkview")) { const code = codeBlock.querySelector("code").innerText || ""; const args = lang.slice(8).trim().split(" "); From 5aedbbfbe0c3a6ac104a81286e5e4f58857039d4 Mon Sep 17 00:00:00 2001 From: OLDREDSTONE Date: Fri, 16 Jan 2026 23:31:09 +0800 Subject: [PATCH 4/8] =?UTF-8?q?[RDView]=20=E4=BF=AE=E5=A4=8D=20hsb=20?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E8=AF=BB=E5=8F=96=E5=BC=82=E5=B8=B8=E5=92=8C?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/rdtkview.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/script/rdtkview.js b/script/rdtkview.js index be302b6..7f6a805 100644 --- a/script/rdtkview.js +++ b/script/rdtkview.js @@ -762,12 +762,15 @@ function createLayerFromBackground(key, bound, color, style, backgroundRepeat = const height = bound.height; const infoLeft = info.bounds.left; const infoTop = info.bounds.top; + const widthScale = width / info.bounds.width; + const heightScale = height / info.bounds.height; layer.style.left = `${(left - pivotX) * style.scale}px`; layer.style.top = `${(top - pivotY) * style.scale}px`; layer.style.width = `${width * style.scale}px`; layer.style.height = `${height * style.scale}px`; - layer.style.backgroundPosition = `-${infoLeft * style.scale}px -${infoTop * style.scale}px`; - layer.style.backgroundSize = `${assetSize.width * width * style.scale}px ${assetSize.height * height * style.scale}px`; + layer.style.backgroundPosition = `-${infoLeft * widthScale * style.scale}px -${infoTop * heightScale * style.scale}px`; + layer.style.backgroundSize = `${assetSize.width * widthScale * style.scale}px ${assetSize.height * heightScale * style.scale}px`; + console.log(layer.style.backgroundSize); } else { bound = bound ?? new Point(0, 0); const left = bound.x; @@ -963,7 +966,6 @@ function createElementEvent(obj, style) { } if (!slices.has(key0)) { if (!slices.has("event_Unknown")) { - console.log(slices); return null; } key0 = "event_Unknown"; @@ -1262,7 +1264,10 @@ function createElementEvent(obj, style) { const top = iconSize / 2 - iconBounds.height * s / 2; const patternLayers = []; const backLayers2 = createBackLayer(new Size(slcinfo.bounds.width, slcinfo.bounds.height), colorOf(obj.tab ?? evinfo.defaultTab), style); - for (let p of obj.pattern ?? "------") { + if (typeof obj.pattern !== "string" || obj.pattern.length !== 6) { + obj.pattern = "------"; + } + for (let p of obj.pattern) { const beatxLayer = createLayerFromBackground(p === "x" ? beatx : beatline, new Rect(left, top, width, iconBounds.height * s), null, style); patternLayers.push(...beatxLayer); left += width; @@ -1511,18 +1516,19 @@ function createElementEvent(obj, style) { if (obj["$style"]) { const hsb = obj["$style"].hsb ?? [ 0, - 0, - 0 + 1, + 1 ]; - if (hsb[0] !== 0 || hsb[1] !== 0 || hsb[2] !== 0) { + if (hsb.length === 3 && (hsb[0] !== 0 || hsb[1] !== 0 || hsb[2] !== 0)) { layersToAdd.forEach((layer) => { + if (!layer.filterData) return; layer.filterData.hue = hsb[0]; layer.filterData.saturation = hsb[1]; layer.filterData.brightness = hsb[2]; }); } layersToAdd.forEach((layer) => { - layer.updateFilter(); + layer.updateFilter?.(); }); } element.onStateChange = (style2) => { From c14a85c46495f39657bacde0dc32b0fbb5761f62 Mon Sep 17 00:00:00 2001 From: kuanpan Date: Sat, 17 Jan 2026 09:46:28 +0800 Subject: [PATCH 5/8] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=87=B3=20images?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- images/hold.jpg | Bin 0 -> 20157 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/hold.jpg diff --git a/images/hold.jpg b/images/hold.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e72f03e274126766edcd6aeac15b66ed214004e GIT binary patch literal 20157 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 literal 0 HcmV?d00001 From 006e2f2ff1ac3edff48440db50b00089c76f0a25 Mon Sep 17 00:00:00 2001 From: kuanpan Date: Sat, 17 Jan 2026 10:29:45 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E5=88=A0=E9=99=A4=20images/hold.jpg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- images/hold.jpg | Bin 20157 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 images/hold.jpg diff --git a/images/hold.jpg b/images/hold.jpg deleted file mode 100644 index 1e72f03e274126766edcd6aeac15b66ed214004e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20157 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 From d922a6fae6040582ae4dc0bd5ce833e88b752647 Mon Sep 17 00:00:00 2001 From: kuanpan Date: Sat, 17 Jan 2026 10:31:20 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=87=B3=20images?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- images/moreoneshothold.png | Bin 0 -> 14579 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/moreoneshothold.png diff --git a/images/moreoneshothold.png b/images/moreoneshothold.png new file mode 100644 index 0000000000000000000000000000000000000000..a933422d76a692e02dcd4c1b953bd5fd3031fd44 GIT binary patch literal 14579 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 Date: Sat, 17 Jan 2026 10:58:29 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20pages/moreoneshotbeats?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/moreoneshotbeats.md | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/pages/moreoneshotbeats.md b/pages/moreoneshotbeats.md index d5712f6..a560277 100644 --- a/pages/moreoneshotbeats.md +++ b/pages/moreoneshotbeats.md @@ -338,6 +338,52 @@ g 0 -1 3 2 #0000[offset=0 1]{ }; ``` +## 长按单发拍 + +长按单发拍第一次出现在`7-1` + +当听到`咻噗`的声音时,说明下一次击拍需要长按到下一个出拍点。 + +在修饰符中选中进度条符号就创建了一个长按单发拍,会多出`间隔`与`长按提示选项`选项。 + +![](../images/moreoneshothold.png) + +对于长按单发拍,一共有四个关键的时间点:十字,出拍点(绿线),按拍点(黄线),长按(紫色格子)。 +```rdtkview 5 3 + { "bar": 1, "beat": 3, "y": 2, "type": "AddOneshotBeat","interval": 2, "tick": 1, "hold": true }, +``` + +- **十字**显示长按单发拍子的提示音。 +- **绿线**代表单发拍会在此响一次。 +- **黄线**表示长按的起始点,也就是说玩家应当从这里开始长按。 +- **紫格**就是此次长按所需的时间。 +- **绿线**与**黄线**之间的间隔就是`拍长`的时间。 +- **十字**与**黄线**或者**绿线**与**紫格**末端之间的间隔就是`间隔`的时间。 + +在`长按提示`有三个选项,分别是:自动、偏早、偏晚。 + +- 选择**偏早**时,`十字`的位置会在`绿线`之前。 +- 选择**偏晚**时,`十字`不会显示,但提示音会与`绿线`重合。 +- 选择**自动**时: +- 若**拍长**小于或等于1,则像`偏早`一样,长按单发拍子的提示音会在`绿线`之前; +- 若**拍长**大于1,则像`偏晚`一样,`十字`不会显示,但提示音会与`绿线`重合。 + +```rdtkview 5 5 + { "bar": 1, "beat": 3, "y": 2, "type": "AddOneshotBeat","interval": 2, "tick": 1, "hold": true }, + { "bar": 1, "beat": 3, "y": 3, "type": "AddOneshotBeat","interval": 2, "tick": 1, "hold": true }, + { "bar": 1, "beat": 3, "y": 4, "type": "AddOneshotBeat","interval": 2, "tick": 1, "hold": true } +``` + +若设计长按单发拍,还必须满足松手音效与提示音不可重叠 + +如果需要在长按单发拍上叠加多个拍子来凸显鼓点,可以将他们的按拍点放在同一位置。 + +```rdtkview 5 3 + { "bar": 1, "beat": 1.5, "y": 2, "tick": 2.5, "type": "AddOneshotBeat" }, + { "bar": 1, "beat": 2.5, "y": 2, "tick": 1.5, "type": "AddOneshotBeat" }, + { "bar": 1, "beat": 3, "y": 2, "type": "AddOneshotBeat","interval": 2, "tick": 1, "hold": true } +``` + 最后我们针对细分拍、冻结拍、灼热拍做一个技术总结: ```rdview 19 7