@@ -15,6 +15,24 @@ function normalizeTag(value) {
1515 return normalizeToken ( value ) . replace ( / [ _ \s ] + / g, "-" ) . replace ( / - + / g, "-" ) ;
1616}
1717
18+ function isThemeEngineClass ( value ) {
19+ const normalized = normalize ( value ) . replace ( / \\ / g, "/" ) ;
20+ if ( ! normalized ) {
21+ return false ;
22+ }
23+ const leaf = normalized . split ( "/" ) . pop ( ) || "" ;
24+ return / ^ t h e m e / i. test ( leaf ) ;
25+ }
26+
27+ function toEngineClassName ( value ) {
28+ const normalized = normalize ( value ) . replace ( / \\ / g, "/" ) ;
29+ if ( ! normalized ) {
30+ return "" ;
31+ }
32+ const leaf = normalized . split ( "/" ) . pop ( ) || "" ;
33+ return normalize ( leaf ) ;
34+ }
35+
1836function levelSortKey ( level ) {
1937 const value = normalize ( level ) ;
2038 const numericMatch = value . match ( / L e v e l \s + ( \d + ) / i) ;
@@ -60,54 +78,6 @@ function normalizeGameHref(value) {
6078 return href ;
6179}
6280
63- function normalizePresetPath ( value ) {
64- const normalized = normalize ( value ) . replace ( / \\ / g, "/" ) ;
65- if ( ! normalized || normalized . includes ( ".." ) ) {
66- return "" ;
67- }
68- if ( normalized . startsWith ( "/samples/" ) ) {
69- return normalized ;
70- }
71- if ( normalized . startsWith ( "/games/" ) ) {
72- return normalized ;
73- }
74- if ( normalized . startsWith ( "samples/" ) ) {
75- return `/${ normalized } ` ;
76- }
77- if ( normalized . startsWith ( "games/" ) ) {
78- return `/${ normalized } ` ;
79- }
80- if ( normalized . startsWith ( "./samples/" ) ) {
81- return `/${ normalized . slice ( 2 ) } ` ;
82- }
83- if ( normalized . startsWith ( "./games/" ) ) {
84- return `/${ normalized . slice ( 2 ) } ` ;
85- }
86- return "" ;
87- }
88-
89- function getExplicitRoundtripPresetPath ( game , toolId ) {
90- const safeToolId = normalizeToken ( toolId ) ;
91- if ( ! safeToolId ) {
92- return "" ;
93- }
94- const mappedEntries = asArray ( game ?. roundtripToolPresets ) ;
95- for ( const entry of mappedEntries ) {
96- if ( ! entry || typeof entry !== "object" ) {
97- continue ;
98- }
99- const mappedToolId = normalizeToken ( entry . toolId ) ;
100- if ( mappedToolId !== safeToolId ) {
101- continue ;
102- }
103- const presetPath = normalizePresetPath ( entry . presetPath ) ;
104- if ( presetPath ) {
105- return presetPath ;
106- }
107- }
108- return "" ;
109- }
110-
11181function buildWorkspaceManagerHref ( gameId ) {
11282 const normalizedGameId = normalize ( gameId ) ;
11383 return normalizedGameId
@@ -126,47 +96,6 @@ function buildToolTokens(toolHints, toolLabelMap) {
12696 . sort ( ( a , b ) => a . label . localeCompare ( b . label , undefined , { sensitivity : "base" } ) ) ;
12797}
12898
129- function buildRoundtripLinks ( game , toolRegistryMap ) {
130- const orderedToolHints = asArray ( game ?. toolHints )
131- . map ( ( entry ) => normalizeToken ( entry ) )
132- . filter ( Boolean )
133- . filter ( ( toolId ) => toolId !== "workspace-manager" ) ;
134- const dedupedToolHints = [ ...new Set ( orderedToolHints ) ] ;
135- const links = [ ] ;
136-
137- dedupedToolHints . forEach ( ( toolId ) => {
138- const tool = toolRegistryMap . get ( toolId ) ;
139- if ( ! tool ) {
140- return ;
141- }
142- const workspaceHref = "/tools/Workspace%20Manager/index.html" ;
143- const query = new URLSearchParams ( ) ;
144- query . set ( "tool" , tool . id ) ;
145- query . set ( "game" , game . id ) ;
146- query . set ( "gameId" , game . id ) ;
147- if ( game . title ) {
148- query . set ( "gameTitle" , game . title ) ;
149- }
150- if ( game . href ) {
151- query . set ( "gameHref" , game . href ) ;
152- }
153- const presetPath = getExplicitRoundtripPresetPath ( game , tool . id ) ;
154- if ( presetPath ) {
155- query . set ( "samplePresetPath" , presetPath ) ;
156- const sampleIdMatch = / s a m p l e - ( \d { 4 } ) - [ ^ . ] + \. j s o n $ / i. exec ( presetPath ) ;
157- if ( sampleIdMatch ?. [ 1 ] ) {
158- query . set ( "sampleId" , sampleIdMatch [ 1 ] ) ;
159- }
160- }
161- query . set ( "workspaceHref" , buildWorkspaceManagerHref ( game . id ) ) ;
162- const href = `${ workspaceHref } ?${ query . toString ( ) } ` ;
163- const label = `Open ${ normalize ( tool . displayName ) || normalize ( tool . name ) || toolId } ` ;
164- links . push ( { toolId, href, label } ) ;
165- } ) ;
166-
167- return links ;
168- }
169-
17099function statusLabel ( status ) {
171100 switch ( status ) {
172101 case "playable" :
@@ -200,7 +129,7 @@ function writePinnedSet(pinnedSet) {
200129 window . localStorage . setItem ( GAMES_PINNED_KEY , JSON . stringify ( [ ...pinnedSet ] . sort ( ) ) ) ;
201130}
202131
203- function buildRows ( metadata , pinnedSet , toolLabelMap , toolRegistryMap ) {
132+ function buildRows ( metadata , pinnedSet , toolLabelMap ) {
204133 const rows = asArray ( metadata ?. games )
205134 . map ( ( game ) => {
206135 const id = normalize ( game ?. id ) ;
@@ -211,19 +140,17 @@ function buildRows(metadata, pinnedSet, toolLabelMap, toolRegistryMap) {
211140 }
212141 const classValues = [ ...new Set ( asArray ( game ?. classValues ) . map ( ( value ) => normalize ( value ) ) . filter ( Boolean ) ) ]
213142 . sort ( ( a , b ) => a . localeCompare ( b , undefined , { sensitivity : "base" } ) ) ;
214- const engineClasses = [ ...new Set ( asArray ( game ?. engineClassesUsed ) . map ( ( value ) => normalize ( value ) ) . filter ( Boolean ) ) ]
143+ const engineClasses = [ ...new Set ( asArray ( game ?. engineClassesUsed )
144+ . map ( ( value ) => normalize ( value ) )
145+ . filter ( Boolean )
146+ . filter ( ( value ) => ! isThemeEngineClass ( value ) ) ) ]
147+ . sort ( ( a , b ) => a . localeCompare ( b , undefined , { sensitivity : "base" } ) ) ;
148+ const engineClassNames = [ ...new Set ( engineClasses . map ( ( value ) => toEngineClassName ( value ) ) . filter ( Boolean ) ) ]
215149 . sort ( ( a , b ) => a . localeCompare ( b , undefined , { sensitivity : "base" } ) ) ;
216150 const tags = [ ...new Set ( asArray ( game ?. tags ) . map ( ( value ) => normalizeTag ( value ) ) . filter ( Boolean ) ) ]
217151 . sort ( ( a , b ) => a . localeCompare ( b , undefined , { sensitivity : "base" } ) ) ;
218152 const href = normalizeGameHref ( game ?. href ) ;
219153 const toolTokens = buildToolTokens ( game ?. toolHints , toolLabelMap ) ;
220- const roundtripLinks = buildRoundtripLinks ( {
221- id,
222- title,
223- href,
224- toolHints : game ?. toolHints ,
225- roundtripToolPresets : game ?. roundtripToolPresets
226- } , toolRegistryMap ) ;
227154 return {
228155 id,
229156 title,
@@ -232,8 +159,8 @@ function buildRows(metadata, pinnedSet, toolLabelMap, toolRegistryMap) {
232159 status : normalize ( game ?. status ) || "planned" ,
233160 classValues,
234161 engineClasses,
162+ engineClassNames,
235163 toolTokens,
236- roundtripLinks,
237164 tags,
238165 preview : normalize ( game ?. preview ) ,
239166 href,
@@ -248,7 +175,7 @@ function buildRows(metadata, pinnedSet, toolLabelMap, toolRegistryMap) {
248175 . filter ( Boolean ) ;
249176
250177 const levels = [ ...new Set ( rows . map ( ( row ) => row . level ) ) ] . sort ( sortLevels ) ;
251- const classes = [ ...new Set ( rows . flatMap ( ( row ) => row . classValues ) ) ] . sort ( ( a , b ) => a . localeCompare ( b , undefined , { sensitivity : "base" } ) ) ;
178+ const classes = [ ...new Set ( rows . flatMap ( ( row ) => row . engineClassNames ) ) ] . sort ( ( a , b ) => a . localeCompare ( b , undefined , { sensitivity : "base" } ) ) ;
252179 const tools = [ ...new Map (
253180 rows . flatMap ( ( row ) => row . toolTokens ) . map ( ( token ) => [ token . value , token . label ] )
254181 ) . entries ( ) ]
@@ -269,7 +196,7 @@ function filterRows(rows, state) {
269196 if ( state . level && row . level !== state . level ) {
270197 return false ;
271198 }
272- if ( state . classValue && ! row . classValues . includes ( state . classValue ) ) {
199+ if ( state . classValue && ! row . engineClassNames . includes ( state . classValue ) ) {
273200 return false ;
274201 }
275202 if ( state . toolId && ! row . toolTokens . some ( ( token ) => token . value === state . toolId ) ) {
@@ -282,7 +209,7 @@ function filterRows(rows, state) {
282209 return true ;
283210 }
284211 const toolText = row . toolTokens . map ( ( token ) => `${ token . label } ${ token . value } ` ) . join ( " " ) ;
285- const haystack = `${ row . level } ${ row . title } ${ row . description } ${ row . classValues . join ( " " ) } ${ toolText } ${ row . tags . join ( " " ) } ` . toLowerCase ( ) ;
212+ const haystack = `${ row . level } ${ row . title } ${ row . description } ${ row . engineClassNames . join ( " " ) } ${ toolText } ${ row . tags . join ( " " ) } ` . toLowerCase ( ) ;
286213 return haystack . includes ( query ) ;
287214 } ) ;
288215}
@@ -327,6 +254,9 @@ function renderCard(row, instanceKey = "main") {
327254 ] . filter ( Boolean ) . join ( "" ) ;
328255
329256 const classEntries = row . engineClasses ;
257+ const toolsUsedText = row . toolTokens . length > 0
258+ ? row . toolTokens . map ( ( token ) => token . label ) . join ( ", " )
259+ : "none" ;
330260 const tagText = row . tags . length > 0 ? row . tags . join ( ", " ) : "none" ;
331261 const workspaceSection = row . workspaceHref
332262 ? `
@@ -343,6 +273,7 @@ function renderCard(row, instanceKey = "main") {
343273 <p>${ escapeHtml ( row . description ) } </p>
344274 ${ workspaceSection }
345275 <p>Tags: ${ escapeHtml ( tagText ) } </p>
276+ <p>Tools Used: ${ escapeHtml ( toolsUsedText ) } </p>
346277 <section class="game-tool-roundtrip">
347278 <h4>Engine Classes Used</h4>
348279 ${ classEntries . length > 0
@@ -436,16 +367,10 @@ export async function initGamesIndex() {
436367 . map ( ( tool ) => [ normalizeToken ( tool . id ) , normalize ( tool . displayName ) || normalize ( tool . name ) || normalize ( tool . id ) ] )
437368 . filter ( ( entry ) => entry [ 0 ] && entry [ 1 ] )
438369 ) ;
439- const toolRegistryMap = new Map (
440- toolRegistry
441- . filter ( ( tool ) => tool . id !== "workspace-manager" )
442- . map ( ( tool ) => [ normalizeToken ( tool . id ) , tool ] )
443- . filter ( ( entry ) => entry [ 0 ] && entry [ 1 ] )
444- ) ;
445370 let pinnedSet = readPinnedSet ( ) ;
446- let model = buildRows ( metadata , pinnedSet , toolLabelMap , toolRegistryMap ) ;
371+ let model = buildRows ( metadata , pinnedSet , toolLabelMap ) ;
447372 setSelect ( levelSelect , model . levels , ( value ) => value ) ;
448- setSelect ( classSelect , model . classes , ( value ) => value . split ( "/" ) . at ( - 1 ) || value ) ;
373+ setSelect ( classSelect , model . classes , ( value ) => value ) ;
449374 setSelect ( toolSelect , model . tools . map ( ( entry ) => entry . value ) , ( value ) => {
450375 const found = model . tools . find ( ( entry ) => entry . value === value ) ;
451376 return found ?. label || value ;
@@ -457,7 +382,7 @@ export async function initGamesIndex() {
457382 }
458383
459384 const apply = ( ) => {
460- model = buildRows ( metadata , pinnedSet , toolLabelMap , toolRegistryMap ) ;
385+ model = buildRows ( metadata , pinnedSet , toolLabelMap ) ;
461386 const state = {
462387 level : normalize ( levelSelect . value ) ,
463388 classValue : normalize ( classSelect . value ) ,
0 commit comments