Sharpee: Cloak of Darkness

Hopefully no one saw the last post I immediately unpublished. It was a mistake. I had asked Claude for a professional assessment and it somehow used "Senior Typescript Developer" as the perspective. I re-prompted as "Senior IF Platform Developer" and got the correct assessment. That just led me to finishing the work, which has finally reached a major milestone. Cloak of Darkness works!
Below is the transcript using a Text Service that emits the raw event messages. Eventually there will be a Text Service that displays an IF standard window, either via WebAssembly or direct to a web client (likely React). The Text Service would use the event data to query the world model for actual descriptions. We do have some system events that aren't hooked in yet. Those would show the parser and validation details for each command.
The story file is 860 lines long and is implemented directly with the standard library. This is sort of the "experienced developer" layer. One of the next steps is to design the fluent Forge layer, which will greatly reduce the author's coding requirements.
Still need to implement that Forge layer, a standard client and Text Service, documentation, and then a larger reference story. There is still a lot of "tree-shaking" to get through.
I'm too tired to truly enjoy the moment, but it is profound.
node run-platform.js
=== Cloak of Darkness (Static Platform) ===
A Sharpee IF demonstration
Moving player a01 to foyer r01
Engine started successfully
> look
=== Turn 1 ===
Game Events:
[IF.EVENT.LOOKED] {"actorId":"a01","locationId":"r01","locationName":"Foyer of the Opera House","isDark":false,"timestamp":1755161981090}
[IF.EVENT.ROOM_DESCRIPTION] {"roomId":"r01","includeContents":true,"verbose":true,"timestamp":1755161981091}
[IF.EVENT.LIST_CONTENTS] {"items":["i01"],"itemNames":["velvet cloak"],"npcs":[],"containers":[],"supporters":[],"other":["i01"],"context":"room","timestamp":1755161981091}
[ACTION.SUCCESS] {"actionId":"if.action.looking","messageId":"contents_list","params":{"items":"velvet cloak","count":1}}
Location: Foyer of the Opera House [r01]
> trace
=== Turn 2 ===
Game Events:
[COMMAND.FAILED] {"reason":"Could not match input to any command pattern","input":"trace"}
Location: Foyer of the Opera House [r01]
Error: Could not match input to any command pattern
> trace parser on
=== Turn 3 ===
Game Events:
[COMMAND.FAILED] {"reason":"Could not match input to any command pattern","input":"trace parser on"}
Location: Foyer of the Opera House [r01]
Error: Could not match input to any command pattern
> examine cloak
=== Turn 4 ===
Game Events:
[IF.EVENT.EXAMINED] {"targetId":"i01","targetName":"velvet cloak","hasDescription":true,"hasBrief":false,"isWearable":true,"isWorn":false}
[ACTION.SUCCESS] {"actionId":"if.action.examining","messageId":"examined_wearable","params":{"description":"A handsome cloak of velvet trimmed with satin, and slightly splattered with raindrops. Its blackness is so deep that it almost seems to suck light from the room.","isWorn":false}}
Location: Foyer of the Opera House [r01]
> trace validation on
=== Turn 5 ===
Game Events:
[COMMAND.FAILED] {"reason":"Could not match input to any command pattern","input":"trace validation on"}
Location: Foyer of the Opera House [r01]
Error: Could not match input to any command pattern
> west
=== Turn 6 ===
Game Events:
[IF.EVENT.ACTOR_EXITED] {"actorId":"a01","direction":"west","toRoom":"r02"}
[IF.EVENT.ACTOR_MOVED] {"direction":"west","fromRoom":"r01","toRoom":"r02","oppositeDirection":"east","firstVisit":true}
[IF.EVENT.ACTOR_ENTERED] {"actorId":"a01","direction":"east","fromRoom":"r01"}
[ACTION.SUCCESS] {"actionId":"if.action.going","messageId":"first_visit","params":{"direction":"west","destination":"Cloakroom"}}
Location: Cloakroom [r02]
> trace parser off
=== Turn 7 ===
Game Events:
[COMMAND.FAILED] {"reason":"Could not match input to any command pattern","input":"trace parser off"}
Location: Cloakroom [r02]
Error: Could not match input to any command pattern
> look
=== Turn 8 ===
Game Events:
[IF.EVENT.LOOKED] {"actorId":"a01","locationId":"r02","locationName":"Cloakroom","isDark":false,"timestamp":1755161981099}
[IF.EVENT.ROOM_DESCRIPTION] {"roomId":"r02","includeContents":true,"verbose":true,"timestamp":1755161981099}
[IF.EVENT.LIST_CONTENTS] {"items":["i01","s01"],"itemNames":["velvet cloak","brass hook"],"npcs":[],"containers":[],"supporters":["s01"],"other":["i01"],"context":"room","timestamp":1755161981099}
[ACTION.SUCCESS] {"actionId":"if.action.looking","messageId":"contents_list","params":{"items":"velvet cloak, brass hook","count":2}}
Location: Cloakroom [r02]
> trace off
=== Turn 9 ===
Game Events:
[COMMAND.FAILED] {"reason":"Could not match input to any command pattern","input":"trace off"}
Location: Cloakroom [r02]
Error: Could not match input to any command pattern
> hang cloak on hook
Cloak hung on hook - bar is now lit
=== Turn 10 ===
Game Events:
[IF.EVENT.PUT_ON] {"itemId":"i01","targetId":"s01","preposition":"on"}
[ACTION.SUCCESS] {"actionId":"if.action.putting","messageId":"put_on","params":{"item":"velvet cloak","surface":"brass hook"}}
Location: Cloakroom [r02]
> east
=== Turn 11 ===
Game Events:
[IF.EVENT.ACTOR_EXITED] {"actorId":"a01","direction":"east","toRoom":"r01"}
[IF.EVENT.ACTOR_MOVED] {"direction":"east","fromRoom":"r02","toRoom":"r01","oppositeDirection":"west","firstVisit":true}
[IF.EVENT.ACTOR_ENTERED] {"actorId":"a01","direction":"west","fromRoom":"r02"}
[ACTION.SUCCESS] {"actionId":"if.action.going","messageId":"first_visit","params":{"direction":"east","destination":"Foyer of the Opera House"}}
Location: Foyer of the Opera House [r01]
> south
=== Turn 12 ===
Game Events:
[IF.EVENT.ACTOR_EXITED] {"actorId":"a01","direction":"south","toRoom":"r03"}
[IF.EVENT.ACTOR_MOVED] {"direction":"south","fromRoom":"r01","toRoom":"r03","oppositeDirection":"north","firstVisit":true}
[IF.EVENT.ACTOR_ENTERED] {"actorId":"a01","direction":"north","fromRoom":"r01"}
[ACTION.SUCCESS] {"actionId":"if.action.going","messageId":"first_visit","params":{"direction":"south","destination":"Foyer Bar"}}
Location: Foyer Bar [r03]
> examine message
=== Turn 13 ===
Game Events:
[IF.EVENT.EXAMINED] {"targetId":"y01","targetName":"message in the sawdust","hasDescription":true,"hasBrief":false,"isReadable":true,"hasText":true}
[ACTION.SUCCESS] {"actionId":"if.action.examining","messageId":"examined_readable","params":{"description":"The message, neatly marked in the sawdust, reads...","text":"You have won!"}}
Location: Foyer Bar [r03]
> read message
=== Turn 14 ===
Game Events:
[IF.EVENT.READ] "You have won!"
[ACTION.SUCCESS] {"actionId":"if.action.reading","messageId":"read_text","params":{"item":"message in the sawdust","text":"You have won!"}}
Location: Foyer Bar [r03]
=== Story Complete ===