mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-04-22 06:09:02 +00:00
refactor: use standard prettier formatting
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import {describe, it, expect} from "vitest"
|
||||
import {compressActions, decompressActions} from "./actions"
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { compressActions, decompressActions } from "./actions";
|
||||
|
||||
describe("layout", function () {
|
||||
const actions = [1023, 255, 256, 42, 32, 532, 8000]
|
||||
const actions = [1023, 255, 256, 42, 32, 532, 8000];
|
||||
|
||||
describe("compression", function () {
|
||||
it("should compress back and forth arrays divisible by 4", function () {
|
||||
expect(decompressActions(compressActions(actions))).toEqual(actions)
|
||||
})
|
||||
})
|
||||
})
|
||||
expect(decompressActions(compressActions(actions))).toEqual(actions);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
* Action codes <32 are invalid.
|
||||
*/
|
||||
export function compressActions(actions: number[]): Uint8Array {
|
||||
const buffer = new Uint8Array(actions.length * 2)
|
||||
let i = 0
|
||||
const buffer = new Uint8Array(actions.length * 2);
|
||||
let i = 0;
|
||||
for (const action of actions) {
|
||||
if (action > 0xff) {
|
||||
buffer[i++] = action >>> 8
|
||||
buffer[i++] = action >>> 8;
|
||||
}
|
||||
buffer[i++] = action & 0xff
|
||||
buffer[i++] = action & 0xff;
|
||||
}
|
||||
return buffer.slice(0, i)
|
||||
return buffer.slice(0, i);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -21,13 +21,13 @@ export function compressActions(actions: number[]): Uint8Array {
|
||||
* @see {compressActions}
|
||||
*/
|
||||
export function decompressActions(raw: Uint8Array): number[] {
|
||||
const actions: number[] = []
|
||||
const actions: number[] = [];
|
||||
for (let i = 0; i < raw.length; i++) {
|
||||
let action = raw[i]
|
||||
let action = raw[i];
|
||||
if (action > 0 && action < 32) {
|
||||
action = (action << 8) | raw[++i]
|
||||
action = (action << 8) | raw[++i];
|
||||
}
|
||||
actions.push(action)
|
||||
actions.push(action);
|
||||
}
|
||||
return actions
|
||||
return actions;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import {describe, it, expect} from "vitest"
|
||||
import {fromBase64, toBase64} from "./base64"
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { fromBase64, toBase64 } from "./base64";
|
||||
|
||||
describe("base64", function () {
|
||||
const data = new Uint8Array([24, 235, 22, 67, 84, 73, 23, 77, 21])
|
||||
const data = new Uint8Array([24, 235, 22, 67, 84, 73, 23, 77, 21]);
|
||||
|
||||
it("should convert back-forth", async function () {
|
||||
expect(await fromBase64(await toBase64(new Blob([data]))).then(it => it.arrayBuffer())).toEqual(
|
||||
data.buffer,
|
||||
)
|
||||
})
|
||||
})
|
||||
expect(
|
||||
await fromBase64(await toBase64(new Blob([data]))).then((it) =>
|
||||
it.arrayBuffer(),
|
||||
),
|
||||
).toEqual(data.buffer);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* meaning some chars are swapped for compatibility
|
||||
*/
|
||||
export async function toBase64(blob: Blob): Promise<string> {
|
||||
return new Promise(async resolve => {
|
||||
const reader = new FileReader()
|
||||
return new Promise(async (resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
resolve(
|
||||
`${(reader.result as string)
|
||||
@@ -14,17 +14,20 @@ export async function toBase64(blob: Blob): Promise<string> {
|
||||
.replaceAll("+", ".")
|
||||
.replaceAll("/", "_")
|
||||
.replaceAll("=", "-")}`,
|
||||
)
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
})
|
||||
);
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
export async function fromBase64(base64: string, fetch = window.fetch): Promise<Blob> {
|
||||
export async function fromBase64(
|
||||
base64: string,
|
||||
fetch = window.fetch,
|
||||
): Promise<Blob> {
|
||||
return fetch(
|
||||
`data:application/octet-stream;base64,${base64
|
||||
.replaceAll(".", "+")
|
||||
.replaceAll("_", "/")
|
||||
.replaceAll("-", "=")}`,
|
||||
).then(it => it.blob())
|
||||
).then((it) => it.blob());
|
||||
}
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
[
|
||||
[
|
||||
600, 47, 45, 515, 297, 601, 119, 562, 103, 122, 602, 107, 118, 109, 99, 603, 114, 298, 32, 101, 604, 105,
|
||||
127, 46, 111, 605, 39, 512, 44, 117, 552, 513, 514, 550, 540, 607, 335, 338, 336, 337, 608, 565, 568, 566,
|
||||
567, 609, 563, 63, 519, 297, 610, 98, 120, 536, 113, 611, 102, 112, 104, 100, 612, 97, 296, 544, 116, 613,
|
||||
108, 299, 106, 110, 614, 121, 516, 59, 115, 553, 517, 518, 551, 542, 616, 336, 338, 335, 337, 617, 566,
|
||||
568, 565, 567
|
||||
600, 47, 45, 515, 297, 601, 119, 562, 103, 122, 602, 107, 118, 109, 99, 603,
|
||||
114, 298, 32, 101, 604, 105, 127, 46, 111, 605, 39, 512, 44, 117, 552, 513,
|
||||
514, 550, 540, 607, 335, 338, 336, 337, 608, 565, 568, 566, 567, 609, 563,
|
||||
63, 519, 297, 610, 98, 120, 536, 113, 611, 102, 112, 104, 100, 612, 97, 296,
|
||||
544, 116, 613, 108, 299, 106, 110, 614, 121, 516, 59, 115, 553, 517, 518,
|
||||
551, 542, 616, 336, 338, 335, 337, 617, 566, 568, 565, 567
|
||||
],
|
||||
[
|
||||
0, 92, 45, 515, 297, 0, 119, 562, 91, 93, 0, 55, 56, 57, 48, 0, 49, 298, 51, 50, 0, 52, 127, 54, 53, 0,
|
||||
96, 512, 61, 124, 0, 513, 514, 550, 540, 0, 569, 572, 570, 571, 0, 565, 568, 566, 567, 0, 563, 63, 519,
|
||||
297, 0, 98, 120, 91, 93, 0, 55, 56, 57, 48, 0, 49, 296, 51, 50, 0, 52, 299, 54, 53, 0, 61, 516, 59, 115,
|
||||
0, 517, 518, 551, 542, 0, 570, 572, 569, 571, 0, 566, 568, 565, 567
|
||||
0, 92, 45, 515, 297, 0, 119, 562, 91, 93, 0, 55, 56, 57, 48, 0, 49, 298, 51,
|
||||
50, 0, 52, 127, 54, 53, 0, 96, 512, 61, 124, 0, 513, 514, 550, 540, 0, 569,
|
||||
572, 570, 571, 0, 565, 568, 566, 567, 0, 563, 63, 519, 297, 0, 98, 120, 91,
|
||||
93, 0, 55, 56, 57, 48, 0, 49, 296, 51, 50, 0, 52, 299, 54, 53, 0, 61, 516,
|
||||
59, 115, 0, 517, 518, 551, 542, 0, 570, 572, 569, 571, 0, 566, 568, 565, 567
|
||||
],
|
||||
[
|
||||
0, 47, 45, 515, 297, 0, 119, 324, 325, 122, 0, 320, 321, 322, 323, 0, 314, 298, 316, 315, 0, 317, 127,
|
||||
319, 318, 0, 39, 512, 44, 117, 552, 513, 514, 0, 540, 0, 335, 338, 336, 337, 0, 569, 572, 570, 571, 0,
|
||||
563, 63, 519, 297, 0, 98, 324, 325, 113, 0, 320, 321, 322, 323, 0, 314, 296, 316, 315, 0, 317, 299, 319,
|
||||
318, 0, 121, 516, 59, 115, 553, 517, 518, 0, 542, 0, 336, 338, 335, 337, 0, 570, 572, 569, 571
|
||||
0, 47, 45, 515, 297, 0, 119, 324, 325, 122, 0, 320, 321, 322, 323, 0, 314,
|
||||
298, 316, 315, 0, 317, 127, 319, 318, 0, 39, 512, 44, 117, 552, 513, 514, 0,
|
||||
540, 0, 335, 338, 336, 337, 0, 569, 572, 570, 571, 0, 563, 63, 519, 297, 0,
|
||||
98, 324, 325, 113, 0, 320, 321, 322, 323, 0, 314, 296, 316, 315, 0, 317,
|
||||
299, 319, 318, 0, 121, 516, 59, 115, 553, 517, 518, 0, 542, 0, 336, 338,
|
||||
335, 337, 0, 570, 572, 569, 571
|
||||
]
|
||||
]
|
||||
|
||||
@@ -1,37 +1,49 @@
|
||||
import {compressActions, decompressActions} from "./actions"
|
||||
import {fromBase64, toBase64} from "$lib/serialization/base64"
|
||||
import { compressActions, decompressActions } from "./actions";
|
||||
import { fromBase64, toBase64 } from "$lib/serialization/base64";
|
||||
|
||||
export interface NewCharaLayout {
|
||||
charaLayoutVersion: 1
|
||||
device: "one" | "lite" | string
|
||||
charaLayoutVersion: 1;
|
||||
device: "one" | "lite" | string;
|
||||
/**
|
||||
* Layers A1-A3, with numeric action codes on each
|
||||
*/
|
||||
layers: [number[], number[], number[]]
|
||||
layers: [number[], number[], number[]];
|
||||
}
|
||||
|
||||
export type CharaLayout = [number[], number[], number[]]
|
||||
export type CharaLayout = [number[], number[], number[]];
|
||||
|
||||
/**
|
||||
* Serialize a layout into a micro package
|
||||
*/
|
||||
export async function serializeLayout(layout: CharaLayout): Promise<Blob> {
|
||||
const items = compressActions(layout.flat())
|
||||
const stream = new Blob([items]).stream().pipeThrough(new CompressionStream("deflate"))
|
||||
return new Response(stream).blob()
|
||||
const items = compressActions(layout.flat());
|
||||
const stream = new Blob([items])
|
||||
.stream()
|
||||
.pipeThrough(new CompressionStream("deflate"));
|
||||
return new Response(stream).blob();
|
||||
}
|
||||
|
||||
export async function deserializeLayout(layout: Blob): Promise<CharaLayout> {
|
||||
const stream = layout.stream().pipeThrough(new DecompressionStream("deflate"))
|
||||
const raw = await new Response(stream).arrayBuffer()
|
||||
const actions = decompressActions(new Uint8Array(raw))
|
||||
return [actions.slice(0, 90), actions.slice(90, 180), actions.slice(180, 270)]
|
||||
const stream = layout
|
||||
.stream()
|
||||
.pipeThrough(new DecompressionStream("deflate"));
|
||||
const raw = await new Response(stream).arrayBuffer();
|
||||
const actions = decompressActions(new Uint8Array(raw));
|
||||
return [
|
||||
actions.slice(0, 90),
|
||||
actions.slice(90, 180),
|
||||
actions.slice(180, 270),
|
||||
];
|
||||
}
|
||||
|
||||
export async function layoutAsUrlComponent(layout: CharaLayout): Promise<string> {
|
||||
return serializeLayout(layout).then(toBase64)
|
||||
export async function layoutAsUrlComponent(
|
||||
layout: CharaLayout,
|
||||
): Promise<string> {
|
||||
return serializeLayout(layout).then(toBase64);
|
||||
}
|
||||
|
||||
export async function layoutFromUrlComponent(base64: string): Promise<CharaLayout> {
|
||||
return fromBase64(base64).then(deserializeLayout)
|
||||
export async function layoutFromUrlComponent(
|
||||
base64: string,
|
||||
): Promise<CharaLayout> {
|
||||
return fromBase64(base64).then(deserializeLayout);
|
||||
}
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
export interface VisualLayout {
|
||||
name: string
|
||||
col: VisualLayoutRow[]
|
||||
name: string;
|
||||
col: VisualLayoutRow[];
|
||||
}
|
||||
|
||||
interface Positionable {
|
||||
offset: [number, number]
|
||||
rotate: number
|
||||
offset: [number, number];
|
||||
rotate: number;
|
||||
}
|
||||
|
||||
export interface VisualLayoutRow extends Positionable {
|
||||
row: Array<VisualLayoutKey | VisualLayoutSwitch>
|
||||
row: Array<VisualLayoutKey | VisualLayoutSwitch>;
|
||||
}
|
||||
|
||||
export interface VisualLayoutKey extends Positionable {
|
||||
key: number
|
||||
size?: [number, number]
|
||||
key: number;
|
||||
size?: [number, number];
|
||||
}
|
||||
|
||||
export interface VisualLayoutSwitch extends Positionable {
|
||||
switch: {
|
||||
n: number
|
||||
e: number
|
||||
w: number
|
||||
s: number
|
||||
d: number
|
||||
}
|
||||
n: number;
|
||||
e: number;
|
||||
w: number;
|
||||
s: number;
|
||||
d: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CompiledLayout {
|
||||
name: string
|
||||
size: [number, number]
|
||||
keys: CompiledLayoutKey[]
|
||||
name: string;
|
||||
size: [number, number];
|
||||
keys: CompiledLayoutKey[];
|
||||
}
|
||||
|
||||
export interface CompiledLayoutKey {
|
||||
id: number
|
||||
shape: "quarter-circle" | "square"
|
||||
cornerRadius: number
|
||||
size: [number, number]
|
||||
pos: [number, number]
|
||||
rotate: number
|
||||
id: number;
|
||||
shape: "quarter-circle" | "square";
|
||||
cornerRadius: number;
|
||||
size: [number, number];
|
||||
pos: [number, number];
|
||||
rotate: number;
|
||||
}
|
||||
|
||||
export function compileLayout(layout: VisualLayout): CompiledLayout {
|
||||
@@ -47,18 +47,18 @@ export function compileLayout(layout: VisualLayout): CompiledLayout {
|
||||
name: layout.name,
|
||||
size: [0, 0],
|
||||
keys: [],
|
||||
}
|
||||
};
|
||||
|
||||
let y = 0
|
||||
for (const {row, offset} of layout.col) {
|
||||
let x = offset?.[0] ?? 0
|
||||
y += offset?.[1] ?? 0
|
||||
let maxHeight = 0
|
||||
let y = 0;
|
||||
for (const { row, offset } of layout.col) {
|
||||
let x = offset?.[0] ?? 0;
|
||||
y += offset?.[1] ?? 0;
|
||||
let maxHeight = 0;
|
||||
for (const info of row) {
|
||||
const [ox, oy] = info.offset || [0, 0]
|
||||
const rotate = info.rotate || 0
|
||||
const [ox, oy] = info.offset || [0, 0];
|
||||
const rotate = info.rotate || 0;
|
||||
if ("key" in info) {
|
||||
const [width, height] = info.size ?? [1, 1]
|
||||
const [width, height] = info.size ?? [1, 1];
|
||||
|
||||
compiled.keys.push({
|
||||
id: info.key,
|
||||
@@ -67,14 +67,19 @@ export function compileLayout(layout: VisualLayout): CompiledLayout {
|
||||
pos: [x + ox, y + oy],
|
||||
cornerRadius: 0.1,
|
||||
rotate,
|
||||
})
|
||||
});
|
||||
|
||||
x += width + ox
|
||||
maxHeight = Math.max(maxHeight, height + oy)
|
||||
x += width + ox;
|
||||
maxHeight = Math.max(maxHeight, height + oy);
|
||||
} else if ("switch" in info) {
|
||||
const cx = x + ox + 1
|
||||
const cy = y + oy + 1
|
||||
for (const [i, id] of [info.switch.s, info.switch.w, info.switch.n, info.switch.e].entries()) {
|
||||
const cx = x + ox + 1;
|
||||
const cy = y + oy + 1;
|
||||
for (const [i, id] of [
|
||||
info.switch.s,
|
||||
info.switch.w,
|
||||
info.switch.n,
|
||||
info.switch.e,
|
||||
].entries()) {
|
||||
compiled.keys.push({
|
||||
id,
|
||||
shape: "quarter-circle",
|
||||
@@ -82,7 +87,7 @@ export function compileLayout(layout: VisualLayout): CompiledLayout {
|
||||
size: [2, 0.6],
|
||||
pos: [cx, cy],
|
||||
rotate: 90 * i + 45,
|
||||
})
|
||||
});
|
||||
}
|
||||
compiled.keys.push({
|
||||
id: info.switch.d,
|
||||
@@ -91,16 +96,16 @@ export function compileLayout(layout: VisualLayout): CompiledLayout {
|
||||
size: [0.8, 0.8],
|
||||
pos: [x + 0.6 + ox, y + 0.6 + oy],
|
||||
rotate: 0,
|
||||
})
|
||||
});
|
||||
|
||||
x += 2 + ox
|
||||
maxHeight = Math.max(maxHeight, 2 + oy)
|
||||
x += 2 + ox;
|
||||
maxHeight = Math.max(maxHeight, 2 + oy);
|
||||
}
|
||||
}
|
||||
y += maxHeight
|
||||
compiled.size[0] = Math.max(compiled.size[0], x)
|
||||
y += maxHeight;
|
||||
compiled.size[0] = Math.max(compiled.size[0], x);
|
||||
}
|
||||
compiled.size[1] = y
|
||||
compiled.size[1] = y;
|
||||
|
||||
return compiled
|
||||
return compiled;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user