jaml-ui 0.20.1 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +1 -1
- package/dist/assets.d.ts +0 -5
- package/dist/assets.js +0 -7
- package/dist/components/JamlCurator.d.ts +1 -2
- package/dist/components/JamlCurator.js +2 -2
- package/dist/hooks/searchWorker.d.ts +1 -0
- package/dist/hooks/searchWorker.js +68 -0
- package/dist/hooks/useSearch.d.ts +1 -1
- package/dist/hooks/useSearch.js +8 -13
- package/dist/render/CanvasRenderer.js +2 -2
- package/dist/ui/hooks.d.ts +13 -0
- package/dist/ui/hooks.js +44 -0
- package/dist/ui/jimbo.css +1099 -1086
- package/dist/ui/panel.d.ts +1 -1
- package/dist/ui/panel.js +7 -6
- package/package.json +1 -1
package/DESIGN.md
CHANGED
|
@@ -203,4 +203,4 @@ JAML-hit items get a GlowRing: `box-shadow: 0 0 0 2px [color], 0 0 10px [color]`
|
|
|
203
203
|
- DON'T add visible scrollbars. Vertical magnetic snap-scroll + horizontal swipe only.
|
|
204
204
|
- DON'T use rounded corners larger than 10px. Balatro is chunky, not bubbly.
|
|
205
205
|
- DON'T use blur-based shadows for depth. Use solid colored box-shadows 80% opaque.
|
|
206
|
-
- DON'T use redundant JS wrappers for `motely-wasm`. Import globally and `motely.boot()` once.
|
|
206
|
+
- DON'T use redundant JS wrappers for `motely-wasm`. Import globally and `motely.boot()` once. Use `?worker&inline` for search workers rather than blob strings, and do not prop-drill `motelyWasmUrl`.
|
package/dist/assets.d.ts
CHANGED
|
@@ -18,8 +18,3 @@ export declare function setJamlAssetBaseUrl(baseUrl: string | null | undefined):
|
|
|
18
18
|
export declare function clearJamlAssetBaseUrl(): void;
|
|
19
19
|
export declare function resolveJamlAssetUrl(asset: JamlAssetKey | JamlAssetFile): string;
|
|
20
20
|
export declare function getDefaultJamlAssetUrlMap(): Readonly<Record<JamlAssetKey, string>>;
|
|
21
|
-
/**
|
|
22
|
-
* Returns the versioned Vercel Blob URL for motely-wasm's Bootsharp module.
|
|
23
|
-
* Pass the same pinned motely-wasm version the app installed/uploaded.
|
|
24
|
-
*/
|
|
25
|
-
export declare function getMotelyWasmUrl(version: string): string;
|
package/dist/assets.js
CHANGED
|
@@ -68,10 +68,3 @@ export function resolveJamlAssetUrl(asset) {
|
|
|
68
68
|
export function getDefaultJamlAssetUrlMap() {
|
|
69
69
|
return defaultAssetUrls;
|
|
70
70
|
}
|
|
71
|
-
/**
|
|
72
|
-
* Returns the versioned Vercel Blob URL for motely-wasm's Bootsharp module.
|
|
73
|
-
* Pass the same pinned motely-wasm version the app installed/uploaded.
|
|
74
|
-
*/
|
|
75
|
-
export function getMotelyWasmUrl(version) {
|
|
76
|
-
return `https://cdn.seedfinder.app/motely-wasm/${version}/index.mjs`;
|
|
77
|
-
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
export interface JamlCuratorProps {
|
|
2
|
-
motelyWasmUrl: string;
|
|
3
2
|
}
|
|
4
|
-
export declare function JamlCurator({
|
|
3
|
+
export declare function JamlCurator({}: JamlCuratorProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -11,10 +11,10 @@ import { useSearch } from "../hooks/useSearch.js";
|
|
|
11
11
|
import { useAnalyzer } from "../hooks/useAnalyzer.js";
|
|
12
12
|
import { JamlSpeedometer } from "./JamlSpeedometer.js";
|
|
13
13
|
const C = JimboColorOption;
|
|
14
|
-
export function JamlCurator({
|
|
14
|
+
export function JamlCurator({}) {
|
|
15
15
|
// Use map editor by default to generate JAML
|
|
16
16
|
const [jamlText, setJamlText] = useState("");
|
|
17
|
-
const search = useSearch(
|
|
17
|
+
const search = useSearch();
|
|
18
18
|
const analyzer = useAnalyzer();
|
|
19
19
|
// Search results pagination
|
|
20
20
|
const [resultIndex, setResultIndex] = useState(0);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import motely, { MotelyWasm, MotelyWasmEvents } from "motely-wasm";
|
|
2
|
+
// Boot motely immediately when this module is loaded
|
|
3
|
+
motely.boot().catch(console.error);
|
|
4
|
+
let activeSearch = null;
|
|
5
|
+
self.addEventListener('message', function (e) {
|
|
6
|
+
const msg = e.data;
|
|
7
|
+
if (msg.type === 'start') {
|
|
8
|
+
const validation = MotelyWasm.validateJaml(msg.jaml);
|
|
9
|
+
if (validation !== 'valid') {
|
|
10
|
+
self.postMessage({ type: 'error', message: validation });
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
function cleanup() {
|
|
14
|
+
MotelyWasmEvents.notifyResult = () => { };
|
|
15
|
+
MotelyWasmEvents.notifyProgress = () => { };
|
|
16
|
+
MotelyWasmEvents.notifyComplete = () => { };
|
|
17
|
+
activeSearch = null;
|
|
18
|
+
}
|
|
19
|
+
MotelyWasmEvents.notifyResult = function (seed, score, tallyColumns) {
|
|
20
|
+
self.postMessage({ type: 'result', seed, score, tallyColumns: Array.from(tallyColumns) });
|
|
21
|
+
};
|
|
22
|
+
MotelyWasmEvents.notifyProgress = function (searched, matching) {
|
|
23
|
+
self.postMessage({ type: 'progress', searched: searched.toString(), matching: matching.toString() });
|
|
24
|
+
};
|
|
25
|
+
MotelyWasmEvents.notifyComplete = function (status, searched, matched) {
|
|
26
|
+
cleanup();
|
|
27
|
+
self.postMessage({ type: 'complete', status, searched: searched.toString(), matched: matched.toString() });
|
|
28
|
+
};
|
|
29
|
+
try {
|
|
30
|
+
const mode = msg.mode || 'random';
|
|
31
|
+
if (mode === 'random') {
|
|
32
|
+
activeSearch = MotelyWasm.startRandomSearch(msg.jaml, msg.count);
|
|
33
|
+
}
|
|
34
|
+
else if (mode === 'aesthetic') {
|
|
35
|
+
activeSearch = MotelyWasm.startAestheticSearch(msg.jaml, msg.aesthetic);
|
|
36
|
+
}
|
|
37
|
+
else if (mode === 'seedList') {
|
|
38
|
+
activeSearch = MotelyWasm.startSeedListSearch(msg.jaml, msg.seeds);
|
|
39
|
+
}
|
|
40
|
+
else if (mode === 'keyword') {
|
|
41
|
+
activeSearch = MotelyWasm.startKeywordSearch(msg.jaml, msg.keywords, msg.padding || '');
|
|
42
|
+
}
|
|
43
|
+
else if (mode === 'sequential') {
|
|
44
|
+
activeSearch = MotelyWasm.startSequentialSearch(msg.jaml, msg.batchCharCount, BigInt(msg.startBatch), BigInt(msg.endBatch));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
cleanup();
|
|
49
|
+
self.postMessage({ type: 'error', message: String(err) });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else if (msg.type === 'stop') {
|
|
53
|
+
if (activeSearch) {
|
|
54
|
+
activeSearch.cancel();
|
|
55
|
+
activeSearch = null;
|
|
56
|
+
self.postMessage({ type: 'cancelled' });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else if (msg.type === 'get_tally_labels') {
|
|
60
|
+
try {
|
|
61
|
+
const labels = MotelyWasm.getTallyLabels(msg.jaml);
|
|
62
|
+
self.postMessage({ type: 'tally_labels', labels: Array.from(labels) });
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
self.postMessage({ type: 'error', message: String(err) });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
@@ -13,7 +13,7 @@ export interface UseSearchState {
|
|
|
13
13
|
seedsPerSecond: number;
|
|
14
14
|
tallyLabels: string[];
|
|
15
15
|
}
|
|
16
|
-
export declare function useSearch(
|
|
16
|
+
export declare function useSearch(): {
|
|
17
17
|
start: (jaml: string, count: number) => void;
|
|
18
18
|
startAesthetic: (jaml: string, aesthetic: number) => void;
|
|
19
19
|
startSeedList: (jaml: string, seeds: string[]) => void;
|
package/dist/hooks/useSearch.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useState, useCallback, useRef, useEffect } from "react";
|
|
3
|
-
import
|
|
4
|
-
function createWorker(
|
|
5
|
-
|
|
6
|
-
const blobUrl = URL.createObjectURL(blob);
|
|
7
|
-
const worker = new Worker(blobUrl);
|
|
8
|
-
worker.postMessage({ type: "init", url: motelyWasmUrl });
|
|
9
|
-
return worker;
|
|
3
|
+
import SearchWorker from "./searchWorker.ts?worker&inline";
|
|
4
|
+
function createWorker() {
|
|
5
|
+
return new SearchWorker();
|
|
10
6
|
}
|
|
11
7
|
const INITIAL_STATE = {
|
|
12
8
|
results: [],
|
|
@@ -17,16 +13,15 @@ const INITIAL_STATE = {
|
|
|
17
13
|
seedsPerSecond: 0,
|
|
18
14
|
tallyLabels: [],
|
|
19
15
|
};
|
|
20
|
-
export function useSearch(
|
|
16
|
+
export function useSearch() {
|
|
21
17
|
const [state, setState] = useState(INITIAL_STATE);
|
|
22
18
|
const workerRef = useRef(null);
|
|
23
|
-
const readyRef = useRef(
|
|
19
|
+
const readyRef = useRef(true); // Worker is ready implicitly since boot is handled by import
|
|
24
20
|
const speedRef = useRef({ lastSearched: 0n, lastTime: 0, ema: 0 });
|
|
25
21
|
useEffect(() => {
|
|
26
|
-
setState((s) => ({ ...s, status: "
|
|
27
|
-
const worker = createWorker(
|
|
22
|
+
setState((s) => ({ ...s, status: "idle" }));
|
|
23
|
+
const worker = createWorker();
|
|
28
24
|
workerRef.current = worker;
|
|
29
|
-
readyRef.current = false;
|
|
30
25
|
worker.onmessage = (e) => {
|
|
31
26
|
const msg = e.data;
|
|
32
27
|
if (msg.type === "ready") {
|
|
@@ -88,7 +83,7 @@ export function useSearch(motelyWasmUrl) {
|
|
|
88
83
|
worker.terminate();
|
|
89
84
|
workerRef.current = null;
|
|
90
85
|
};
|
|
91
|
-
}, [
|
|
86
|
+
}, []);
|
|
92
87
|
const sendStart = useCallback((payload) => {
|
|
93
88
|
const worker = workerRef.current;
|
|
94
89
|
if (!worker)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useJamlCardRenderer } from "../ui/hooks.js";
|
|
4
4
|
export function JamlCardRenderer({ layers, invert = false, className = "", hoverTilt = false }) {
|
|
5
5
|
const { canvasRef, containerStyle, canvasStyle, handlers } = useJamlCardRenderer({
|
|
@@ -7,5 +7,5 @@ export function JamlCardRenderer({ layers, invert = false, className = "", hover
|
|
|
7
7
|
invert,
|
|
8
8
|
hoverTilt
|
|
9
9
|
});
|
|
10
|
-
return (
|
|
10
|
+
return (_jsxs("div", { className: className, style: { ...containerStyle, position: "relative" }, children: [_jsx("canvas", { ref: canvasRef, style: canvasStyle }), hoverTilt && (_jsx("div", { style: { position: "absolute", inset: "-15px", zIndex: 10, cursor: "pointer" }, ...handlers })), !hoverTilt && (_jsx("div", { style: { position: "absolute", inset: "0", zIndex: 10 }, ...handlers }))] }));
|
|
11
11
|
}
|
package/dist/ui/hooks.d.ts
CHANGED
|
@@ -87,3 +87,16 @@ export declare function useJamlIdeDrag(filter: JamlVisualFilter, onChange: (filt
|
|
|
87
87
|
hoverZone: string | null;
|
|
88
88
|
onDragStart: (e: React.MouseEvent | React.TouchEvent, clause: JamlVisualClause, fromZone: JamlZone) => void;
|
|
89
89
|
};
|
|
90
|
+
/**
|
|
91
|
+
* Provides a magnetic 3D tilt effect for DOM elements, replicating the 'juice' of Balatro cards.
|
|
92
|
+
* Ensures the hit-detection area remains stable by separating container events from the transformed style.
|
|
93
|
+
*/
|
|
94
|
+
export declare function useDOMMagneticTilt(enabled?: boolean): {
|
|
95
|
+
handlers: {
|
|
96
|
+
onPointerEnter: ((event: React.PointerEvent) => void) | undefined;
|
|
97
|
+
onPointerLeave: (() => void) | undefined;
|
|
98
|
+
onPointerMove: ((event: React.PointerEvent) => void) | undefined;
|
|
99
|
+
};
|
|
100
|
+
tiltStyle: React.CSSProperties;
|
|
101
|
+
isHovered: boolean;
|
|
102
|
+
};
|
package/dist/ui/hooks.js
CHANGED
|
@@ -551,3 +551,47 @@ export function useJamlIdeDrag(filter, onChange, rootRef) {
|
|
|
551
551
|
onDragStart,
|
|
552
552
|
};
|
|
553
553
|
}
|
|
554
|
+
/**
|
|
555
|
+
* Provides a magnetic 3D tilt effect for DOM elements, replicating the 'juice' of Balatro cards.
|
|
556
|
+
* Ensures the hit-detection area remains stable by separating container events from the transformed style.
|
|
557
|
+
*/
|
|
558
|
+
export function useDOMMagneticTilt(enabled = true) {
|
|
559
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
560
|
+
const [transform, setTransform] = useState('none');
|
|
561
|
+
const onPointerEnter = (event) => {
|
|
562
|
+
if (!enabled || event.pointerType === 'touch')
|
|
563
|
+
return;
|
|
564
|
+
setIsHovered(true);
|
|
565
|
+
};
|
|
566
|
+
const onPointerLeave = () => {
|
|
567
|
+
if (!enabled)
|
|
568
|
+
return;
|
|
569
|
+
setIsHovered(false);
|
|
570
|
+
setTransform('none');
|
|
571
|
+
};
|
|
572
|
+
const onPointerMove = (event) => {
|
|
573
|
+
if (!enabled || event.pointerType === 'touch')
|
|
574
|
+
return;
|
|
575
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
576
|
+
const x = event.clientX - rect.left;
|
|
577
|
+
const y = event.clientY - rect.top;
|
|
578
|
+
const rotateY = (x / rect.width) * 12 - 6;
|
|
579
|
+
const rotateX = (y / rect.height) * -16 + 8;
|
|
580
|
+
const juiceScale = 1.05;
|
|
581
|
+
const juiceY = -2; // slight move up
|
|
582
|
+
setTransform(`perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(${juiceScale}) translateY(${juiceY}px)`);
|
|
583
|
+
};
|
|
584
|
+
const handlers = {
|
|
585
|
+
onPointerEnter: enabled ? onPointerEnter : undefined,
|
|
586
|
+
onPointerLeave: enabled ? onPointerLeave : undefined,
|
|
587
|
+
onPointerMove: enabled ? onPointerMove : undefined,
|
|
588
|
+
};
|
|
589
|
+
const tiltStyle = {
|
|
590
|
+
transition: enabled && !isHovered ? 'transform 0.4s ease, box-shadow 0.4s ease-out' : 'transform 0.1s ease-out',
|
|
591
|
+
transform: enabled ? (isHovered ? transform : 'none') : undefined,
|
|
592
|
+
transformStyle: enabled ? 'preserve-3d' : undefined,
|
|
593
|
+
transformOrigin: enabled ? 'center center' : undefined,
|
|
594
|
+
willChange: enabled ? 'transform' : undefined,
|
|
595
|
+
};
|
|
596
|
+
return { handlers, tiltStyle, isHovered };
|
|
597
|
+
}
|