Spaces:
Running on Zero
Running on Zero
| """ | |
| Platform-specific templates (PlayCanvas, Twine, HTML tests) | |
| """ | |
| TestmedialoadinHTML = """ | |
| <div> | |
| <p>This is a placeholder to test use as an all-media loader for ease of prototyping. Seems gradio HTML doesnt support loading local assets or my file path is wrong</p> | |
| </div> | |
| <div style="display: flex; justify-content: space-between; margin-bottom: 20px;"> | |
| <div style="width: 30%;"> | |
| <img src="testmedia/Flash scribble SDXL - random squiggles as roads.webp" alt="Random squiggles as roads" style="width: 100%; height: auto;"> | |
| </div> | |
| <div style="width: 30%;"> | |
| <video width="100%" height="auto" controls> | |
| <source src="testmedia/SVD - random squiggles as roads video 004484.mp4" type="video/mp4"> | |
| Your browser does not support the video tag. | |
| </video> | |
| </div> | |
| <div style="width: 30%;"> | |
| <audio controls style="width: 100%;"> | |
| <source src="testmedia/Stable Audio - Raindrops, output.wav" type="audio/wav"> | |
| Your browser does not support the audio element. | |
| </audio> | |
| </div> | |
| </div> | |
| """ | |
| #-------------------------#-------------------------#-------------------------#------------------------- | |
| playcanvasstorymanager = """ | |
| // storyManager.js | |
| var StoryManager = pc.createScript('storyManager'); | |
| StoryManager.attributes.add('storyConfig', { | |
| type: 'asset', | |
| assetType: 'json', | |
| title: 'Story Config' | |
| }); | |
| // Initialize function | |
| StoryManager.prototype.initialize = function() { | |
| this.currentState = null; | |
| this.storyData = null; | |
| console.log('Initializing StoryManager'); | |
| if (this.storyConfig) { | |
| // Primary Path: Asset assigned via script attributes | |
| console.log('Loading storyConfig asset via script attributes:', this.storyConfig); | |
| this.app.assets.load(this.storyConfig); | |
| this.storyConfig.ready(function () { | |
| if (this.storyConfig.resource) { | |
| console.log('storyConfig.json loaded successfully via script attributes:', this.storyConfig.resource); | |
| this.storyData = this.storyConfig.resource; | |
| this.startStory('arrival'); // Starting state | |
| } else { | |
| console.error('Failed to load storyConfig.json via script attributes.'); | |
| } | |
| }.bind(this)); | |
| } else { | |
| // Fallback Path: Programmatically find and load 'storyConfig.json' | |
| console.warn('Story Config asset is not assigned via script attributes. Attempting programmatic loading.'); | |
| var assetName = 'storyConfig.json'; // Ensure this matches exactly with the asset name in PlayCanvas | |
| var asset = this.app.assets.find(assetName); | |
| if (asset) { | |
| console.log('Found asset programmatically:', assetName); | |
| if (!asset.loaded) { | |
| console.log('Asset not loaded. Initiating load...'); | |
| this.app.assets.load(asset); | |
| } else { | |
| console.log('Asset already loaded.'); | |
| } | |
| asset.ready(function () { | |
| if (asset.resource) { | |
| console.log('storyConfig.json loaded successfully programmatically:', asset.resource); | |
| this.storyData = asset.resource; | |
| this.startStory('arrival'); // Starting state | |
| } else { | |
| console.error('storyConfig.json resource is undefined after loading.'); | |
| } | |
| }.bind(this)); | |
| } else { | |
| console.error('storyConfig.json not found in assets programmatically.'); | |
| // Optionally, you can implement further fallback mechanisms or alert the user | |
| } | |
| } | |
| // Bind events regardless of asset loading method | |
| this.bindEvents(); | |
| }; | |
| // Function to start or transition to a new state | |
| StoryManager.prototype.startStory = function(stateKey) { | |
| console.log('Starting story state:', stateKey); | |
| if (!this.storyData) { | |
| console.error('Story data is not loaded yet.'); | |
| return; | |
| } | |
| var state = this.storyData['singingCompetition'][stateKey]; | |
| if (!state) { | |
| console.error('State not found in storyData:', stateKey); | |
| return; | |
| } | |
| this.currentState = stateKey; | |
| this.displayState(state); | |
| }; | |
| // Function to display the current state | |
| StoryManager.prototype.displayState = function(state) { | |
| console.log('Displaying state:', this.currentState); | |
| // Emit an event to update the UI | |
| this.app.fire('story:display', { | |
| description: state.description, | |
| choices: state.choices | |
| }); | |
| }; | |
| // Function to handle choices | |
| StoryManager.prototype.makeChoice = function(choice) { | |
| console.log('Making choice:', choice); | |
| var current = this.storyData['singingCompetition'][this.currentState]; | |
| var nextStateKey = current.transitions[choice]; | |
| if (nextStateKey) { | |
| this.startStory(nextStateKey); | |
| } else { | |
| console.error('Transition not found for choice:', choice); | |
| } | |
| }; | |
| // Listen for choice selections from UI | |
| StoryManager.prototype.onChoiceSelected = function(choice) { | |
| this.makeChoice(choice); | |
| }; | |
| // Bind the choice selection event | |
| StoryManager.prototype.bindEvents = function() { | |
| console.log('Binding UI choice selection event'); | |
| this.app.on('ui:choiceSelected', this.onChoiceSelected, this); | |
| }; | |
| """ | |
| playcanvasuimanager = """ | |
| var UIManager = pc.createScript('uiManager'); | |
| UIManager.attributes.add('descriptionElement', { type: 'entity' }); | |
| UIManager.attributes.add('choicesContainer', { type: 'entity' }); | |
| UIManager.attributes.add('choiceButtonPrefab', { type: 'asset', assetType: 'template' }); | |
| UIManager.attributes.add('buttonSpacing', { type: 'number', default: 10 }); | |
| UIManager.attributes.add('buttonWidth', { type: 'number', default: 200 }); | |
| UIManager.attributes.add('buttonHeight', { type: 'number', default: 50 }); | |
| UIManager.prototype.initialize = function() { | |
| console.log('Initializing UIManager'); | |
| this.app.on('story:display', this.onStoryDisplay, this); | |
| this.validateSetup(); | |
| testsituation = { | |
| description: 'Test description', | |
| choices: ['Choice 1', 'Choice 2', 'Choice 3'] | |
| } | |
| configstart = { | |
| "singingCompetition": { | |
| "arrival": { | |
| "description": "You arrive at the grand auditorium, the stage illuminated and buzzing with excitement. Contestants and spectators alike fill the hall, eager for the night's performances.", | |
| "events": [], | |
| "choices": ["register for the competition", "explore the backstage area", "sit in the audience"], | |
| "transitions": { | |
| "register for the competition": "registration", | |
| "explore the backstage area": "backstage", | |
| "sit in the audience": "audienceSeat" | |
| }, | |
| "media": [], | |
| "developernotes": [] | |
| }, | |
| }, | |
| } | |
| // Test event (remove in production) | |
| setTimeout(() => { | |
| this.app.fire('story:display', configstart["singingCompetition"]["arrival"]); //, testsituation); | |
| }, 2000); | |
| }; | |
| UIManager.prototype.validateSetup = function() { | |
| if (!this.descriptionElement) { | |
| console.error('Description Element is not assigned'); | |
| } | |
| if (!this.choicesContainer) { | |
| console.error('Choices Container is not assigned'); | |
| } | |
| if (!this.choiceButtonPrefab) { | |
| console.error('Choice Button Prefab is not assigned'); | |
| } else if (this.choiceButtonPrefab.type !== 'template') { | |
| console.error('Choice Button Prefab must be a template asset'); | |
| } | |
| }; | |
| UIManager.prototype.onStoryDisplay = function(data) { | |
| console.log('UIManager received story:display event:', data); | |
| // if (!data || !data.description || !Array.isArray(data.choices)) { | |
| // console.error('Invalid data received in story:display event'); | |
| // return; | |
| // } | |
| this.updateDescription(data.description); | |
| this.updateChoices(data.choices); | |
| }; | |
| UIManager.prototype.updateDescription = function(description) { | |
| if (this.descriptionElement && this.descriptionElement.element) { | |
| this.descriptionElement.element.text = description; | |
| console.log('Description updated'); | |
| } else { | |
| console.warn('Unable to update description: Invalid Description Element'); | |
| } | |
| }; | |
| UIManager.prototype.updateChoices = function(choices) { | |
| if (!this.choicesContainer || !this.choiceButtonPrefab) { | |
| console.error('Unable to update choices: Missing Choices Container or Choice Button Prefab'); | |
| return; | |
| } | |
| // Clear previous choices | |
| while (this.choicesContainer.children.length > 0) { | |
| this.choicesContainer.children[0].destroy(); | |
| } | |
| if (choices.length === 0) { | |
| console.log('No choices available for this state.'); | |
| // Optionally, display a "Restart" or "Exit" button | |
| return; | |
| } | |
| // Calculate total width of all buttons plus spacing | |
| var totalWidth = choices.length * this.buttonWidth + (choices.length - 1) * this.buttonSpacing; | |
| // Create new choice buttons | |
| choices.forEach((choice, index) => { | |
| var button = this.choiceButtonPrefab.resource.instantiate(); | |
| this.choicesContainer.addChild(button); | |
| // Set button size | |
| if (button.element) { | |
| button.element.width = this.buttonWidth; | |
| button.element.height = this.buttonHeight; | |
| } | |
| // Position the button | |
| var xPosition = (index * (this.buttonWidth + this.buttonSpacing)) - (totalWidth / 2) + (this.buttonWidth / 2); | |
| button.setLocalPosition(xPosition, 0, 0); | |
| var buttonText = button.findByName('ButtonText'); | |
| if (buttonText && buttonText.element) { | |
| buttonText.element.text = choice; | |
| } | |
| var buttonComponent = button.button; | |
| if (buttonComponent) { | |
| buttonComponent.on('click', () => { | |
| console.log('Choice selected:', choice); | |
| this.app.fire('ui:choiceSelected', choice); | |
| }); | |
| } else { | |
| console.warn(`Button component missing for choice: ${choice}`); | |
| } | |
| }); | |
| console.log('Choices updated'); | |
| }; | |
| """ | |
| ExampleTwineFileStructureasInitialPrompt = """:: StoryData | |
| { | |
| "ifid": "12345678-9abc-def0-1234-56789abcdef0", | |
| "format": "SugarCube", | |
| "format-version": "2.35.0", | |
| "start": "Startup" | |
| } | |
| :: Startup [startup] | |
| <<set $role = "" >> | |
| <<set $guardReputation = 0>> | |
| <<set $guardAuthority = 0>> | |
| <<set $merchantWealth = 0>> | |
| <<set $merchantSecurity = 0>> | |
| <<set $villagerKnowledge = 0>> | |
| <<set $villagerTrust = 0>> | |
| <<set $guardApproach = "" >> | |
| <<set $merchantAction = "" >> | |
| <<set $villagerAction = "" >> | |
| Welcome to the story! | |
| This time, your character’s **stats** will matter. Your decisions will affect these metrics, which will shape the final outcome. | |
| [[Choose Your Role|Choose Role]] | |
| :: Choose Role | |
| You can experience the upcoming events as one of three roles: | |
| * [[Be a Guard|SetGuard]] | |
| * [[Be a Merchant|SetMerchant]] | |
| * [[Be a Villager|SetVillager]] | |
| :: SetGuard | |
| <<set $role = "Guard">> | |
| <<set $guardReputation = 5>> | |
| <<set $guardAuthority = 5>> | |
| You don the Guard’s mantle. Your starting stats: | |
| **Reputation:** 5 | |
| **Authority:** 5 | |
| <<goto "Market Riot">> | |
| :: SetMerchant | |
| <<set $role = "Merchant">> | |
| <<set $merchantWealth = 10>> | |
| <<set $merchantSecurity = 3>> | |
| You take the role of a Merchant. Your starting stats: | |
| **Wealth:** 10 | |
| **Security:** 3 | |
| <<goto "Market Riot">> | |
| :: SetVillager | |
| <<set $role = "Villager">> | |
| <<set $villagerKnowledge = 2>> | |
| <<set $villagerTrust = 5>> | |
| You become a Villager. Your starting stats: | |
| **Knowledge:** 2 | |
| **Trust:** 5 | |
| <<goto "Market Riot">> | |
| :: Market Riot | |
| The marketplace is in chaos. Shouts and screams echo between the stalls. | |
| <<if $role === "Guard">> | |
| You see your fellow guards struggling to hold the line. This is your moment to either prove your dedication or risk your standing. | |
| **Current Stats:** Reputation: $guardReputation, Authority: $guardAuthority | |
| <<endif>> | |
| <<if $role === "Merchant">> | |
| Overturned carts and scattered goods mean losses. How you respond could preserve or squander your wealth and security. | |
| **Current Stats:** Wealth: $merchantWealth, Security: $merchantSecurity | |
| <<endif>> | |
| <<if $role === "Villager">> | |
| Your neighbors panic. How you handle this crisis could increase your knowledge of the town’s issues or build trust among the people. | |
| **Current Stats:** Knowledge: $villagerKnowledge, Trust: $villagerTrust | |
| <<endif>> | |
| [[Observe more details|Market Details]] | |
| [[View Stats|Stats]] | |
| :: Market Details | |
| The riot intensifies. Guards form a barrier, vendors cry for help, and villagers seek shelter. | |
| <<if $role === "Guard">> | |
| A suspicious figure darts behind a stall. You can: | |
| * [[Pursue the figure|GuardAction_Pursue]] | |
| * [[Hold the line|GuardAction_Hold]] | |
| <<endif>> | |
| <<if $role === "Merchant">> | |
| Your ledger is underfoot. | |
| * [[Retrieve the ledger (risking harm)|MerchantAction_Retrieve]] | |
| * [[Seek safety and abandon the ledger|MerchantAction_Safety]] | |
| <<endif>> | |
| <<if $role === "Villager">> | |
| Rumors swirl about corrupt officials. | |
| * [[Listen and gather info|VillagerAction_Listen]] | |
| * [[Calm the crowd and dispel rumors|VillagerAction_Calm]] | |
| <<endif>> | |
| [[View Stats|Stats]] | |
| :: GuardAction_Pursue | |
| <<set $guardApproach = "pursue">> | |
| <<set $guardReputation += 2>> | |
| <<set $guardAuthority -= 1>> | |
| You chase the suspicious figure, boosting your reputation but weakening your authority for leaving your post. | |
| [[Next|Market Aftermath]] | |
| :: GuardAction_Hold | |
| <<set $guardApproach = "hold">> | |
| <<set $guardReputation -= 1>> | |
| <<set $guardAuthority += 2>> | |
| You hold the line, reinforcing your authority but losing a bit of daring reputation. | |
| [[Next|Market Aftermath]] | |
| :: MerchantAction_Retrieve | |
| <<set $merchantAction = "retrieve">> | |
| <<set $merchantWealth += 1>> | |
| <<set $merchantSecurity -= 2>> | |
| You dive into danger, salvaging your ledger (+Wealth) but feeling less secure. | |
| [[Next|Market Aftermath]] | |
| :: MerchantAction_Safety | |
| <<set $merchantAction = "safety">> | |
| <<set $merchantWealth -= 2>> | |
| <<set $merchantSecurity += 1>> | |
| You choose personal safety over profit, losing some wealth but feeling more secure. | |
| [[Next|Market Aftermath]] | |
| :: VillagerAction_Listen | |
| <<set $villagerAction = "listen">> | |
| <<set $villagerKnowledge += 3>> | |
| <<set $villagerTrust -= 1>> | |
| You gather information quietly, increasing knowledge but losing a bit of trust. | |
| [[Next|Market Aftermath]] | |
| :: VillagerAction_Calm | |
| <<set $villagerAction = "calm">> | |
| <<set $villagerKnowledge -= 1>> | |
| <<set $villagerTrust += 2>> | |
| You try to calm everyone, increasing trust at the expense of missing out on details. | |
| [[Next|Market Aftermath]] | |
| :: Market Aftermath | |
| As the riot disperses, the final scene reflects both your role and your stats: | |
| <<if $role === "Guard">> | |
| **Final Stats:** Reputation: $guardReputation, Authority: $guardAuthority | |
| <<if $guardApproach === "pursue">> | |
| You found clues about instigators. Your higher reputation means the captain respects your initiative, even if your authority slipped. | |
| <<elseif $guardApproach === "hold">> | |
| You maintained order. Solid authority assures your superiors you’re reliable, though less bold than some. | |
| <<endif>> | |
| <<endif>> | |
| <<if $role === "Merchant">> | |
| **Final Stats:** Wealth: $merchantWealth, Security: $merchantSecurity | |
| <<if $merchantAction === "retrieve">> | |
| Your ledger ensures long-term financial potential despite feeling more vulnerable now. | |
| <<elseif $merchantAction === "safety">> | |
| You’re poorer but safer, alive to rebuild another day. | |
| <<endif>> | |
| <<endif>> | |
| <<if $role === "Villager">> | |
| **Final Stats:** Knowledge: $villagerKnowledge, Trust: $villagerTrust | |
| <<if $villagerAction === "listen">> | |
| With greater knowledge, you’re poised to influence future events, though some neighbors mistrust your quiet gathering of intel. | |
| <<elseif $villagerAction === "calm">> | |
| Higher trust ensures your opinions hold weight in the community, even if you know fewer specifics. | |
| <<endif>> | |
| <<endif>> | |
| **Try playing again to see how different choices shape your stats and outcomes.** | |
| [[Restart|Startup]] | |
| [[View Stats|Stats]] | |
| :: Stats | |
| **Your Stats:** | |
| <<if $role === "Guard">>> | |
| - Reputation: $guardReputation | |
| - Authority: $guardAuthority | |
| <<endif>> | |
| <<if $role === "Merchant">>> | |
| - Wealth: $merchantWealth | |
| - Security: $merchantSecurity | |
| <<endif>> | |
| <<if $role === "Villager">>> | |
| - Knowledge: $villagerKnowledge | |
| - Trust: $villagerTrust | |
| <<endif>> | |
| [[Return|Market Aftermath]] | |
| """ | |
| #-------------------------#-------------------------#-------------------------#------------------------- | |