jaml-ui 1.0.2 → 2.0.0

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.
Files changed (49) hide show
  1. package/README.md +1 -15
  2. package/dist/assets/searchPoolWorker-CGxhF1pC.js +2 -0
  3. package/dist/assets/searchPoolWorker-CGxhF1pC.js.map +1 -0
  4. package/dist/chunks/{motelyItemFormats-Dyq1BINO.js → runtime-CW7XHgOy.js} +465 -278
  5. package/dist/chunks/runtime-CW7XHgOy.js.map +1 -0
  6. package/dist/chunks/searchPoolWorker-CEdClSPb.js +11 -0
  7. package/dist/chunks/searchPoolWorker-CEdClSPb.js.map +1 -0
  8. package/dist/chunks/{ui-LfKBGL5-.js → ui-CyhuNM51.js} +736 -680
  9. package/dist/chunks/ui-CyhuNM51.js.map +1 -0
  10. package/dist/components/JamlAestheticSelector.d.ts +1 -1
  11. package/dist/components/JamlIdeToolbar.d.ts +2 -3
  12. package/dist/components/JimmolateEditor.d.ts +47 -0
  13. package/dist/components/SeedFinderApp.d.ts +1 -1
  14. package/dist/components/jamlMap/JokerPicker.d.ts +2 -2
  15. package/dist/components/jamlMap/MysterySlot.d.ts +2 -2
  16. package/dist/components/jamlMap/jokerRarity.d.ts +6 -0
  17. package/dist/decode/motelyItemDecoder.d.ts +0 -2
  18. package/dist/hooks/useSearch.d.ts +3 -3
  19. package/dist/hooks/useSearchPool.d.ts +1 -1
  20. package/dist/index.d.ts +1 -4
  21. package/dist/index.js +12835 -4177
  22. package/dist/index.js.map +1 -1
  23. package/dist/lib/jaml/jamlLangCodemirror.d.ts +13 -0
  24. package/dist/lib/motely/motelyCompatEnums.d.ts +349 -0
  25. package/dist/lib/motely/runtime.d.ts +7 -4
  26. package/dist/lib/types.d.ts +1 -1
  27. package/dist/motely.d.ts +3 -2
  28. package/dist/motely.js +48 -220
  29. package/dist/motely.js.map +1 -1
  30. package/dist/r3f/Card3D.d.ts +55 -0
  31. package/dist/r3f/CardTable.d.ts +35 -0
  32. package/dist/r3f.d.ts +2 -0
  33. package/dist/ui/JimboPicker.d.ts +28 -0
  34. package/dist/ui/hooks.d.ts +1 -3
  35. package/dist/ui/jimbo.css +1 -1
  36. package/dist/ui.d.ts +1 -0
  37. package/dist/ui.js +3 -2
  38. package/package.json +25 -19
  39. package/dist/assets/searchPoolWorker-DHh9a5GD.js +0 -40
  40. package/dist/assets/searchPoolWorker-DHh9a5GD.js.map +0 -1
  41. package/dist/chunks/motelyItemFormats-Dyq1BINO.js.map +0 -1
  42. package/dist/chunks/searchPoolWorker-DgRqVj_q.js +0 -8
  43. package/dist/chunks/searchPoolWorker-DgRqVj_q.js.map +0 -1
  44. package/dist/chunks/ui-LfKBGL5-.js.map +0 -1
  45. package/dist/components/JamlCurator.d.ts +0 -1
  46. package/dist/components/Jamlyzer.d.ts +0 -8
  47. package/dist/hooks/useAnalyzer.d.ts +0 -16
  48. package/dist/lib/hooks/useSeedAnalyzer.d.ts +0 -13
  49. package/dist/lib/utils.d.ts +0 -2
package/README.md CHANGED
@@ -68,7 +68,7 @@ That's the whole integration. `useSearch` handles boot guarding, search lifecycl
68
68
 
69
69
  ## Package exports
70
70
 
71
- Five subpath entries, each a barrel. The public API is exactly what they re-export.
71
+ Four subpath entries, each a barrel. The public API is exactly what they re-export.
72
72
 
73
73
  | Entry | What's in it | When you import it |
74
74
  | ----- | ------------ | ------------------ |
@@ -76,7 +76,6 @@ Five subpath entries, each a barrel. The public API is exactly what they re-expo
76
76
  | `jaml-ui/ui` | Jimbo design system (JimboPanel, JimboButton, JimboModal, tokens) | Building custom Balatro-styled UI |
77
77
  | `jaml-ui/core` | Sprite metadata, asset URLs, canvas `Layer` — pure, **no React, no motely-wasm** | Next.js server components, server-side rendering |
78
78
  | `jaml-ui/motely` | Re-exports `bootsharp` + `Motely` from motely-wasm, plus item-decode helpers and `useJamlLibrary` | Direct motely-wasm access, file-system mount |
79
- | `jaml-ui/r3f` | 3D card via React Three Fiber | Optional, has its own peer deps |
80
79
 
81
80
  ```tsx
82
81
  import { JamlGameCard, useSearch } from "jaml-ui";
@@ -223,18 +222,6 @@ import {
223
222
  } from "jaml-ui/motely";
224
223
  ```
225
224
 
226
- ## 3D card (optional)
227
-
228
- ```bash
229
- npm install three @react-three/fiber @react-three/drei @react-spring/three
230
- ```
231
-
232
- ```tsx
233
- import { Card3D } from "jaml-ui/r3f";
234
-
235
- <Card3D itemName="Blueprint" />
236
- ```
237
-
238
225
  ## Next.js
239
226
 
240
227
  - Use `jaml-ui/core` from server components — it has no React and no motely-wasm imports.
@@ -255,7 +242,6 @@ import { Card3D } from "jaml-ui/r3f";
255
242
  | `motely-wasm` | All search/analyzer/decode functionality | No (direct dep) |
256
243
  | `react-icons` | Components that render icons | Yes |
257
244
  | `@rewaffle/bootsharp-file-system` | `useJamlLibrary` folder mount | Yes |
258
- | `three`, `@react-three/fiber`, `@react-three/drei`, `@react-spring/three` | `jaml-ui/r3f` only | Yes |
259
245
 
260
246
  ## Troubleshooting
261
247
 
@@ -0,0 +1,2 @@
1
+ import{Program as e}from"motely-wasm/motely/wasm";import t from"motely-wasm";import{IFileMounter as n}from"motely-wasm/bootsharp/file-system";let r=()=>!0;e.jimmolatePredicate=e=>r(e.seed,e.score,[...e.tallies]);function i(t){r=t,e.jimmolateEnabled=!0}let a=null;async function o(){if(a)return a;if(t.getStatus()===t.BootStatus.Standby)return a=(async()=>{try{(await import(`@rewaffle/bootsharp-file-system`)).init(n)}catch{}await t.boot()})(),a}const s=globalThis;let c=null,l=[],u=0;function d(){for(let e of l)e();l=[]}function f(){d();let t=e=>{s.postMessage({type:`result`,workerIndex:u,seed:e.seed,score:e.score,tallyColumns:Array.from(e.tallies)})};e.onScoredResult.subscribe(t),l.push(()=>e.onScoredResult.unsubscribe(t));let n=e=>{s.postMessage({type:`progress`,workerIndex:u,searched:Number(e.seedsSearched),matching:Number(e.matchingSeeds),percent:e.percentComplete,seedsPerMs:e.seedsPerMillisecond})};e.onProgress.subscribe(n),l.push(()=>e.onProgress.unsubscribe(n));let r=e=>{s.postMessage({type:`match`,workerIndex:u,seed:e})};e.onSeedMatch.subscribe(r),l.push(()=>e.onSeedMatch.unsubscribe(r))}function p(e,t){return typeof t.deck==`number`&&(e.deck=t.deck),typeof t.stake==`number`&&(e.stake=t.stake),e}function m(t){let n=p(e.fromJaml(t.jaml),t);switch(t.mode){case`aesthetic`:return e.runAestheticSearch(n,t.aesthetic??0);case`seedlist`:return n.seeds=t.seeds??[],e.runSeedListSearch(n);case`random`:{let r=typeof t.count==`number`&&t.count>0?t.count:0;return e.runRandomSearch(n,r)}case`sequential`:{let r=typeof t.startBatchIndex==`string`?BigInt(t.startBatchIndex):void 0,i=typeof t.endBatchIndex==`string`?BigInt(t.endBatchIndex):void 0,a=typeof t.batchCharacterCount==`number`?t.batchCharacterCount:void 0;return e.runSequentialSearch(n,r,i,a)}default:return e.runAestheticSearch(n,0)}}s.onmessage=async e=>{let t=e.data;if(t.type===`stop`){c?.cancel(),d(),s.postMessage({type:`cancelled`,workerIndex:u});return}if(t.type===`start`){u=t.workerIndex;try{if(await o(),t.predicateStr)try{let e=Function(`seed`,`score`,`tallies`,`return (${t.predicateStr})(seed, score, tallies);`);i((t,n,r)=>e(t,n,r))}catch(e){console.error(`Failed to compile worker Jimmolate predicate:`,e)}f(),c?.cancel();let e=m(t);e.start(),c=e;try{await e.waitForCompletionAsync(),s.postMessage({type:`complete`,workerIndex:u,status:e.isCompleted?`Completed`:`Cancelled`,total:Number(e.totalSeedsSearched),matched:Number(e.matchingSeeds)})}finally{d(),c=null}}catch(e){d(),c=null,s.postMessage({type:`error`,workerIndex:u,message:e instanceof Error?e.message:String(e)})}}},s.postMessage({type:`ready`});
2
+ //# sourceMappingURL=searchPoolWorker-CGxhF1pC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchPoolWorker-CGxhF1pC.js","names":[],"sources":["../../src/lib/motely/runtime.ts","../../src/hooks/searchPoolWorker.ts"],"sourcesContent":["import bootsharp from \"motely-wasm\";\nimport { Program as Motely } from \"motely-wasm/motely/wasm\";\nimport type { MotelyScoredSeedResult } from \"motely-wasm/motely\";\nimport { IFileMounter } from \"motely-wasm/bootsharp/file-system\";\n\nexport type MotelyRuntimeStatus = \"idle\" | \"booting\" | \"ready\" | \"error\";\n\n// Jimmolate predicate dispatcher.\n//\n// Bootsharp snapshots [Import] bindings at boot() — assigning `Motely.jimmolatePredicate`\n// AFTER boot is a silent no-op, so the C# side calls an unbound import and the\n// predicate never runs. The correct order (pre-boot bind, post-boot enable) is the\n// one exercised by Motely.Wasm/tests/jimmolate.test.mjs, and the rule is in the\n// Bootsharp docs: imported members \"have to be assigned before booting the runtime.\"\n//\n// So we bind a STABLE dispatcher here at module load (this runs on import, always\n// before any ensureMotelyReady()/boot() call) and swap the inner predicate per\n// search via setJimmolateProbe(). `jimmolateEnabled` is a C# [Export] property, so\n// setting it after boot is fine — only this [Import] must be pre-bound.\n//\n// motely-wasm 20.x replaced the live-context probe with a predicate over the\n// SCORED result ({ seed, score, tallies }) — C# does the work, the predicate\n// decides. We surface that as (seed, score, tallies) so the common case\n// (`seed.startsWith(\"A\")`) keeps its shape.\ntype JimmolateProbe = (seed: string, score: number, tallies: number[]) => boolean;\nlet currentProbe: JimmolateProbe = () => true;\nMotely.jimmolatePredicate = (result: MotelyScoredSeedResult) =>\n currentProbe(result.seed, result.score, [...result.tallies]);\n\n/** Swap the active Jimmolate predicate and enable filtering. Safe before or after boot. */\nexport function setJimmolateProbe(pred: JimmolateProbe): void {\n currentProbe = pred;\n Motely.jimmolateEnabled = true;\n}\n\n/** Reset to pass-through and disable filtering (the engine's default: every survivor matches). */\nexport function clearJimmolateProbe(): void {\n currentProbe = () => true;\n Motely.jimmolateEnabled = false;\n}\n\n// Must match the path the host serves motely-wasm's bin/ at.\n// Used by main-thread hooks, workers, and Storybook staticDir alike.\n// The Storybook staticDir in .storybook/main.ts serves it here.\n// Next.js consumers must serve it at this path too (e.g. via a catch-all route).\n// A bare \"/bin\" would 404 in every deployment context.\nexport const MOTELY_BIN_PATH = \"/motely-wasm/bin\";\n\n// File System extension (optional peer `@rewaffle/bootsharp-file-system`).\n//\n// fs.init() binds the IFileMounter [Import], which — like the Jimmolate probe\n// above and EVERY Bootsharp [Import] — must be assigned BEFORE boot()\n// (Bootsharp docs: extensions/file-system). The package is an OPTIONAL peer, so\n// we dynamically import it and swallow its absence: consumers without it simply\n// get no library mount (useJamlLibrary reports status \"unsupported\").\n//\n// This MUST live in the one centralized boot path, not in a component effect.\n// ~8 callers (useSearch, the workers, useAnalyzer, Jamlyzer, …) each trigger\n// boot via ensureMotelyReady(); whichever fires first wins. If fs.init() sat in\n// useJamlLibrary's useEffect it would lose that race and the mounter would never\n// be bound pre-boot — which is exactly why the library mount silently failed.\nlet fileSystemReady = false;\nlet fileSystemError: unknown = null;\n\n/** True once the optional File System extension was bound before boot. */\nexport function isFileSystemReady(): boolean {\n return fileSystemReady;\n}\n\n/** The error from a failed or absent File System init, if any. */\nexport function getFileSystemError(): unknown {\n return fileSystemError;\n}\n\n// Single boot promise: fs.init() (pre-boot) → boot(), run exactly once and\n// awaited by every caller, so the ordering holds no matter who boots first.\nlet bootPromise: Promise<void> | null = null;\n\nexport async function ensureMotelyReady(): Promise<void> {\n if (bootPromise) return bootPromise;\n if (bootsharp.getStatus() !== bootsharp.BootStatus.Standby) return;\n bootPromise = (async () => {\n // Pre-boot: bind the optional File System mounter if it's installed.\n try {\n // @vite-ignore — optional peer; may be absent on disk. Keep it a\n // runtime import() so Vite's dev import-analysis (Storybook, demo)\n // doesn't try to resolve it at transform time and hard-fail. When\n // missing it throws here and is swallowed → status \"unsupported\".\n // (The library build externalizes it via PEER_EXTERNALS regardless.)\n const fs = await import(/* @vite-ignore */ \"@rewaffle/bootsharp-file-system\");\n fs.init(IFileMounter);\n fileSystemReady = true;\n } catch (error) {\n fileSystemError = error;\n }\n // motely-wasm is an EMBEDDED build (the runtime is inlined into the JS as\n // base64 — see dist/generated/resources.g.mjs), so boot() takes no args and\n // needs no served binaries. The old boot(\"/motely-wasm/bin\") was leftover\n // sideloaded config and 404'd in every context.\n await bootsharp.boot();\n })();\n return bootPromise;\n}\n","/// <reference lib=\"webworker\" />\n\n// Pool worker. Each instance boots its own motely-wasm runtime (single-threaded\n// per Bootsharp 0.8 post-#203 — no SAB, no COOP/COEP). The owning `useSearchPool`\n// hook is responsible for partitioning the input space and assigning each worker\n// a disjoint slice via the fields on PoolStartMessage. This worker just runs\n// what it is told.\nimport { Program as Motely } from \"motely-wasm/motely/wasm\";\nimport type { IMotelySearch, MotelyProgress, MotelyScoredSeedResult } from \"motely-wasm/motely\";\nimport type { MotelyDeck, MotelyStake } from \"motely-wasm/motely/enums\";\nimport type { JamlAesthetic, JamlConfig } from \"motely-wasm/motely/filters/jaml\";\nimport { ensureMotelyReady, setJimmolateProbe } from \"../lib/motely/runtime.js\";\n\nconst self = globalThis as typeof globalThis & DedicatedWorkerGlobalScope;\n\nexport type PoolSearchMode = \"random\" | \"seedlist\" | \"sequential\" | \"aesthetic\";\n\nexport interface PoolStartMessage {\n type: \"start\";\n workerIndex: number;\n workerCount: number;\n mode: PoolSearchMode;\n jaml: string;\n count?: number;\n seeds?: string[];\n batchCharacterCount?: number;\n startBatchIndex?: string;\n endBatchIndex?: string;\n aesthetic?: number;\n deck?: number;\n stake?: number;\n predicateStr?: string;\n}\n\nexport interface PoolStopMessage {\n type: \"stop\";\n}\n\nexport type PoolInboundMessage = PoolStartMessage | PoolStopMessage;\n\nexport interface PoolReadyMessage {\n type: \"ready\";\n}\n\nexport interface PoolResultMessage {\n type: \"result\";\n workerIndex: number;\n seed: string;\n score: number;\n tallyColumns: number[];\n}\n\nexport interface PoolMatchMessage {\n type: \"match\";\n workerIndex: number;\n seed: string;\n}\n\nexport interface PoolProgressMessage {\n type: \"progress\";\n workerIndex: number;\n searched: number;\n matching: number;\n percent: number;\n seedsPerMs: number;\n}\n\nexport interface PoolCompleteMessage {\n type: \"complete\";\n workerIndex: number;\n status: \"Completed\" | \"Cancelled\";\n total: number;\n matched: number;\n}\n\nexport interface PoolCancelledMessage {\n type: \"cancelled\";\n workerIndex: number;\n}\n\nexport interface PoolErrorMessage {\n type: \"error\";\n workerIndex: number;\n message: string;\n}\n\nexport type PoolOutboundMessage =\n | PoolReadyMessage\n | PoolResultMessage\n | PoolMatchMessage\n | PoolProgressMessage\n | PoolCompleteMessage\n | PoolCancelledMessage\n | PoolErrorMessage;\n\nlet currentSearch: IMotelySearch | null = null;\nlet unsubscribers: Array<() => void> = [];\nlet workerIndex = 0;\n\nfunction detachListeners(): void {\n for (const off of unsubscribers) off();\n unsubscribers = [];\n}\n\nfunction attachListeners(): void {\n detachListeners();\n\n const onResult = (result: MotelyScoredSeedResult) => {\n self.postMessage({\n type: \"result\",\n workerIndex,\n seed: result.seed,\n score: result.score,\n tallyColumns: Array.from(result.tallies),\n } satisfies PoolResultMessage);\n };\n Motely.onScoredResult.subscribe(onResult);\n unsubscribers.push(() => Motely.onScoredResult.unsubscribe(onResult));\n\n const onProgress = (progress: MotelyProgress) => {\n self.postMessage({\n type: \"progress\",\n workerIndex,\n searched: Number(progress.seedsSearched),\n matching: Number(progress.matchingSeeds),\n percent: progress.percentComplete,\n seedsPerMs: progress.seedsPerMillisecond,\n } satisfies PoolProgressMessage);\n };\n Motely.onProgress.subscribe(onProgress);\n unsubscribers.push(() => Motely.onProgress.unsubscribe(onProgress));\n\n const onSeedMatch = (seed: string) => {\n self.postMessage({\n type: \"match\",\n workerIndex,\n seed,\n } satisfies PoolMatchMessage);\n };\n Motely.onSeedMatch.subscribe(onSeedMatch);\n unsubscribers.push(() => Motely.onSeedMatch.unsubscribe(onSeedMatch));\n}\n\n// deck/stake are config fields now; the worker is single-threaded, so the old\n// withThreadCount(1) is dropped (it was a no-op here).\nfunction applyCommonOverrides(config: JamlConfig, message: PoolStartMessage): JamlConfig {\n if (typeof message.deck === \"number\") {\n config.deck = message.deck as MotelyDeck;\n }\n if (typeof message.stake === \"number\") {\n config.stake = message.stake as MotelyStake;\n }\n return config;\n}\n\nfunction configureSettings(message: PoolStartMessage): IMotelySearch {\n const config = applyCommonOverrides(Motely.fromJaml(message.jaml), message);\n\n switch (message.mode) {\n case \"aesthetic\":\n return Motely.runAestheticSearch(config, (message.aesthetic ?? 0) as JamlAesthetic);\n case \"seedlist\": {\n config.seeds = message.seeds ?? [];\n return Motely.runSeedListSearch(config);\n }\n case \"random\": {\n const count = typeof message.count === \"number\" && message.count > 0 ? message.count : 0;\n return Motely.runRandomSearch(config, count);\n }\n case \"sequential\": {\n const start = typeof message.startBatchIndex === \"string\" ? BigInt(message.startBatchIndex) : undefined;\n const end = typeof message.endBatchIndex === \"string\" ? BigInt(message.endBatchIndex) : undefined;\n const batchChars = typeof message.batchCharacterCount === \"number\" ? message.batchCharacterCount : undefined;\n return Motely.runSequentialSearch(config, start, end, batchChars);\n }\n default:\n return Motely.runAestheticSearch(config, 0 as JamlAesthetic);\n }\n}\n\nself.onmessage = async (event: MessageEvent) => {\n const data = event.data as PoolInboundMessage;\n\n if (data.type === \"stop\") {\n currentSearch?.cancel();\n detachListeners();\n self.postMessage({ type: \"cancelled\", workerIndex } satisfies PoolCancelledMessage);\n return;\n }\n\n if (data.type !== \"start\") return;\n\n workerIndex = data.workerIndex;\n\n try {\n await ensureMotelyReady();\n\n if (data.predicateStr) {\n try {\n const pred = new Function(\"seed\", \"score\", \"tallies\", `return (${data.predicateStr})(seed, score, tallies);`) as (seed: string, score: number, tallies: number[]) => boolean;\n setJimmolateProbe((seed, score, tallies) => pred(seed, score, tallies));\n } catch (err) {\n console.error(\"Failed to compile worker Jimmolate predicate:\", err);\n }\n }\n\n attachListeners();\n\n currentSearch?.cancel();\n const search = configureSettings(data);\n search.start();\n currentSearch = search;\n\n try {\n await search.waitForCompletionAsync();\n self.postMessage({\n type: \"complete\",\n workerIndex,\n status: search.isCompleted ? \"Completed\" : \"Cancelled\",\n total: Number(search.totalSeedsSearched),\n matched: Number(search.matchingSeeds),\n } satisfies PoolCompleteMessage);\n } finally {\n detachListeners();\n currentSearch = null;\n }\n } catch (error) {\n detachListeners();\n currentSearch = null;\n self.postMessage({\n type: \"error\",\n workerIndex,\n message: error instanceof Error ? error.message : String(error),\n } satisfies PoolErrorMessage);\n }\n};\n\nself.postMessage({ type: \"ready\" } satisfies PoolReadyMessage);\n"],"mappings":"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"}