@origingame/create-game 0.0.0-stage → 0.1.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.
- package/README.md +57 -2
- package/archetypes/README.md +99 -0
- package/archetypes/idle/.origin/setup +14 -0
- package/archetypes/idle/LICENSES.md +12 -0
- package/archetypes/idle/README.md +234 -0
- package/archetypes/idle/assets/audio/buy.wav +0 -0
- package/archetypes/idle/assets/audio/milestone.wav +0 -0
- package/archetypes/idle/assets/audio/nova.wav +0 -0
- package/archetypes/idle/assets/audio/orbit.wav +0 -0
- package/archetypes/idle/assets/audio/tap.wav +0 -0
- package/archetypes/idle/assets/audio/ui-close.ogt +9 -0
- package/archetypes/idle/assets/audio/ui-error.ogt +9 -0
- package/archetypes/idle/assets/audio/ui-open.ogt +9 -0
- package/archetypes/idle/assets/audio/ui-press.ogt +9 -0
- package/archetypes/idle/assets/audio/ui-success.ogt +9 -0
- package/archetypes/idle/assets/fonts/NotoSansSC-subset.ttf +0 -0
- package/archetypes/idle/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
- package/archetypes/idle/assets/fonts/OFL.txt +93 -0
- package/archetypes/idle/assets/fx/drift.ogt +21 -0
- package/archetypes/idle/assets/fx/milestone.ogt +21 -0
- package/archetypes/idle/assets/fx/nova.ogt +22 -0
- package/archetypes/idle/assets/fx/stars.ogt +20 -0
- package/archetypes/idle/assets/fx/tap.ogt +23 -0
- package/archetypes/idle/assets/looks/idle.ogt +17 -0
- package/archetypes/idle/assets/skins/sparkorb/ChakraPetch-BoldItalic.ttf +0 -0
- package/archetypes/idle/assets/skins/sparkorb/ChakraPetch-BoldItalic.ttf.ogt +9 -0
- package/archetypes/idle/assets/skins/sparkorb/LICENSES.md +19 -0
- package/archetypes/idle/assets/skins/sparkorb/OFL.txt +95 -0
- package/archetypes/idle/assets/skins/sparkorb/Orbitron-Medium.ttf +0 -0
- package/archetypes/idle/assets/skins/sparkorb/Orbitron-Medium.ttf.ogt +9 -0
- package/archetypes/idle/assets/skins/sparkorb/Rajdhani-Bold.ttf +0 -0
- package/archetypes/idle/assets/skins/sparkorb/Rajdhani-Bold.ttf.ogt +9 -0
- package/archetypes/idle/assets/skins/sparkorb/atlas.png +0 -0
- package/archetypes/idle/assets/skins/sparkorb/atlas.png.ogt +7 -0
- package/archetypes/idle/assets/skins/sparkorb/icons.png +0 -0
- package/archetypes/idle/assets/skins/sparkorb/icons.png.ogt +7 -0
- package/archetypes/idle/assets/skins/sparkorb/skin.ogt +113 -0
- package/archetypes/idle/assets/sprites/glow.png +0 -0
- package/archetypes/idle/assets/sprites/glow.png.ogt +8 -0
- package/archetypes/idle/assets/sprites/mote-crystal.png +0 -0
- package/archetypes/idle/assets/sprites/mote-crystal.png.ogt +7 -0
- package/archetypes/idle/assets/sprites/mote-ember.png +0 -0
- package/archetypes/idle/assets/sprites/mote-ember.png.ogt +7 -0
- package/archetypes/idle/assets/sprites/mote-star.png +0 -0
- package/archetypes/idle/assets/sprites/mote-star.png.ogt +7 -0
- package/archetypes/idle/assets/sprites/mote-storm.png +0 -0
- package/archetypes/idle/assets/sprites/mote-storm.png.ogt +7 -0
- package/archetypes/idle/assets/sprites/orb.png +0 -0
- package/archetypes/idle/assets/sprites/orb.png.ogt +7 -0
- package/archetypes/idle/assets/sprites/spark.png +0 -0
- package/archetypes/idle/assets/sprites/spark.png.ogt +7 -0
- package/archetypes/idle/assets/strings/en.ogt +62 -0
- package/archetypes/idle/assets/strings/zh-CN.ogt +62 -0
- package/archetypes/idle/gitattributes +22 -0
- package/archetypes/idle/host.d.ts +46 -0
- package/archetypes/idle/package.json +18 -0
- package/archetypes/idle/project.ogt +14 -0
- package/archetypes/idle/references/metal/card.png +0 -0
- package/archetypes/idle/references/metal/orbit.png +0 -0
- package/archetypes/idle/references/metal/title.png +0 -0
- package/archetypes/idle/src/components.ts +139 -0
- package/archetypes/idle/src/main.ts +247 -0
- package/archetypes/idle/src/numbers.ts +126 -0
- package/archetypes/idle/src/systems.ts +340 -0
- package/archetypes/idle/src/ui.ts +412 -0
- package/archetypes/idle/tests/away.og.ts +42 -0
- package/archetypes/idle/tests/flow.og.ts +57 -0
- package/archetypes/idle/tests/frames.og.ts +33 -0
- package/archetypes/idle/tests/frames.ts +134 -0
- package/archetypes/idle/tests/lib.ts +74 -0
- package/archetypes/idle/tests/milestone.og.ts +32 -0
- package/archetypes/idle/tests/nova.og.ts +52 -0
- package/archetypes/idle/tests/offline.og.ts +60 -0
- package/archetypes/idle/tests/pad.og.ts +55 -0
- package/archetypes/idle/tests/pause.og.ts +68 -0
- package/archetypes/idle/tests/phone.og.ts +50 -0
- package/archetypes/idle/tests/replay.og.ts +28 -0
- package/archetypes/idle/tools/make-assets.py +448 -0
- package/archetypes/idle/tools/oglite.py +285 -0
- package/archetypes/idle/tsconfig.json +17 -0
- package/archetypes/match3/.origin/setup +14 -0
- package/archetypes/match3/LICENSES.md +7 -0
- package/archetypes/match3/README.md +205 -0
- package/archetypes/match3/assets/audio/cascade.wav +0 -0
- package/archetypes/match3/assets/audio/clear.wav +0 -0
- package/archetypes/match3/assets/audio/lost.wav +0 -0
- package/archetypes/match3/assets/audio/refused.wav +0 -0
- package/archetypes/match3/assets/audio/select.wav +0 -0
- package/archetypes/match3/assets/audio/swap.wav +0 -0
- package/archetypes/match3/assets/audio/won.wav +0 -0
- package/archetypes/match3/assets/fonts/OFL.txt +93 -0
- package/archetypes/match3/assets/fonts/ui.ttf +0 -0
- package/archetypes/match3/assets/fonts/ui.ttf.ogt +11 -0
- package/archetypes/match3/assets/scenes/main.ogt +24 -0
- package/archetypes/match3/assets/sprites/backdrop.png +0 -0
- package/archetypes/match3/assets/sprites/board.ogt +21 -0
- package/archetypes/match3/assets/sprites/cells.ogt +7 -0
- package/archetypes/match3/assets/sprites/cells.png +0 -0
- package/archetypes/match3/assets/sprites/cells.png.ogt +7 -0
- package/archetypes/match3/assets/sprites/gems.ogt +75 -0
- package/archetypes/match3/assets/sprites/gems.png +0 -0
- package/archetypes/match3/assets/sprites/panel.png +0 -0
- package/archetypes/match3/assets/sprites/ring.png +0 -0
- package/archetypes/match3/gitattributes +22 -0
- package/archetypes/match3/host.d.ts +46 -0
- package/archetypes/match3/package.json +18 -0
- package/archetypes/match3/project.ogt +18 -0
- package/archetypes/match3/references/metal/cascade.png +0 -0
- package/archetypes/match3/references/metal/clearing.png +0 -0
- package/archetypes/match3/references/metal/dealt.png +0 -0
- package/archetypes/match3/src/art.ts +54 -0
- package/archetypes/match3/src/board.ts +112 -0
- package/archetypes/match3/src/components.ts +95 -0
- package/archetypes/match3/src/layout.ts +25 -0
- package/archetypes/match3/src/main.ts +199 -0
- package/archetypes/match3/src/systems.ts +631 -0
- package/archetypes/match3/tests/drag.og.ts +31 -0
- package/archetypes/match3/tests/endings.og.ts +40 -0
- package/archetypes/match3/tests/frames.og.ts +49 -0
- package/archetypes/match3/tests/frames.ts +134 -0
- package/archetypes/match3/tests/hidpi.og.ts +41 -0
- package/archetypes/match3/tests/lib.ts +64 -0
- package/archetypes/match3/tests/replay.og.ts +28 -0
- package/archetypes/match3/tests/sounds.og.ts +50 -0
- package/archetypes/match3/tests/swap.og.ts +67 -0
- package/archetypes/match3/tools/make-assets.py +404 -0
- package/archetypes/match3/tools/oglite.py +285 -0
- package/archetypes/match3/tsconfig.json +17 -0
- package/archetypes/rhythm/.origin/setup +14 -0
- package/archetypes/rhythm/LICENSES.md +13 -0
- package/archetypes/rhythm/README.md +235 -0
- package/archetypes/rhythm/assets/audio/bass0.wav +0 -0
- package/archetypes/rhythm/assets/audio/bass1.wav +0 -0
- package/archetypes/rhythm/assets/audio/bass2.wav +0 -0
- package/archetypes/rhythm/assets/audio/bass3.wav +0 -0
- package/archetypes/rhythm/assets/audio/chords0.wav +0 -0
- package/archetypes/rhythm/assets/audio/chords1.wav +0 -0
- package/archetypes/rhythm/assets/audio/chords2.wav +0 -0
- package/archetypes/rhythm/assets/audio/chords3.wav +0 -0
- package/archetypes/rhythm/assets/audio/clear.wav +0 -0
- package/archetypes/rhythm/assets/audio/click.wav +0 -0
- package/archetypes/rhythm/assets/audio/drums.wav +0 -0
- package/archetypes/rhythm/assets/audio/fail.wav +0 -0
- package/archetypes/rhythm/assets/audio/leadA.wav +0 -0
- package/archetypes/rhythm/assets/audio/leadB.wav +0 -0
- package/archetypes/rhythm/assets/audio/miss.wav +0 -0
- package/archetypes/rhythm/assets/audio/tap0.wav +0 -0
- package/archetypes/rhythm/assets/audio/tap1.wav +0 -0
- package/archetypes/rhythm/assets/audio/tap2.wav +0 -0
- package/archetypes/rhythm/assets/audio/ui-close.ogt +9 -0
- package/archetypes/rhythm/assets/audio/ui-error.ogt +9 -0
- package/archetypes/rhythm/assets/audio/ui-open.ogt +9 -0
- package/archetypes/rhythm/assets/audio/ui-press.ogt +9 -0
- package/archetypes/rhythm/assets/audio/ui-success.ogt +9 -0
- package/archetypes/rhythm/assets/charts/neon-pulse.ogt +919 -0
- package/archetypes/rhythm/assets/fonts/NotoSansSC-subset.ttf +0 -0
- package/archetypes/rhythm/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
- package/archetypes/rhythm/assets/fonts/OFL.txt +93 -0
- package/archetypes/rhythm/assets/fx/hit.ogt +22 -0
- package/archetypes/rhythm/assets/skins/lanebeat/ChakraPetch-Medium.ttf +0 -0
- package/archetypes/rhythm/assets/skins/lanebeat/ChakraPetch-Medium.ttf.ogt +9 -0
- package/archetypes/rhythm/assets/skins/lanebeat/JetBrainsMono-Regular.ttf +0 -0
- package/archetypes/rhythm/assets/skins/lanebeat/JetBrainsMono-Regular.ttf.ogt +9 -0
- package/archetypes/rhythm/assets/skins/lanebeat/LICENSES.md +17 -0
- package/archetypes/rhythm/assets/skins/lanebeat/OFL.txt +95 -0
- package/archetypes/rhythm/assets/skins/lanebeat/Orbitron-Bold.ttf +0 -0
- package/archetypes/rhythm/assets/skins/lanebeat/Orbitron-Bold.ttf.ogt +9 -0
- package/archetypes/rhythm/assets/skins/lanebeat/atlas.png +0 -0
- package/archetypes/rhythm/assets/skins/lanebeat/atlas.png.ogt +7 -0
- package/archetypes/rhythm/assets/skins/lanebeat/icons.png +0 -0
- package/archetypes/rhythm/assets/skins/lanebeat/icons.png.ogt +7 -0
- package/archetypes/rhythm/assets/skins/lanebeat/skin.ogt +110 -0
- package/archetypes/rhythm/assets/sprites/lane.png +0 -0
- package/archetypes/rhythm/assets/sprites/lane.png.ogt +7 -0
- package/archetypes/rhythm/assets/sprites/note.png +0 -0
- package/archetypes/rhythm/assets/sprites/note.png.ogt +7 -0
- package/archetypes/rhythm/assets/sprites/ring.png +0 -0
- package/archetypes/rhythm/assets/sprites/ring.png.ogt +7 -0
- package/archetypes/rhythm/assets/sprites/spark.png +0 -0
- package/archetypes/rhythm/assets/sprites/spark.png.ogt +7 -0
- package/archetypes/rhythm/assets/strings/en.ogt +61 -0
- package/archetypes/rhythm/assets/strings/zh-CN.ogt +61 -0
- package/archetypes/rhythm/gitattributes +22 -0
- package/archetypes/rhythm/host.d.ts +46 -0
- package/archetypes/rhythm/package.json +18 -0
- package/archetypes/rhythm/project.ogt +14 -0
- package/archetypes/rhythm/references/metal/highway.png +0 -0
- package/archetypes/rhythm/references/metal/results.png +0 -0
- package/archetypes/rhythm/references/metal/title.png +0 -0
- package/archetypes/rhythm/src/components.ts +147 -0
- package/archetypes/rhythm/src/main.ts +202 -0
- package/archetypes/rhythm/src/systems.ts +490 -0
- package/archetypes/rhythm/src/ui.ts +421 -0
- package/archetypes/rhythm/tests/band.og.ts +45 -0
- package/archetypes/rhythm/tests/calibrate.og.ts +49 -0
- package/archetypes/rhythm/tests/clear.og.ts +51 -0
- package/archetypes/rhythm/tests/fail.og.ts +40 -0
- package/archetypes/rhythm/tests/flow.og.ts +54 -0
- package/archetypes/rhythm/tests/frames.og.ts +35 -0
- package/archetypes/rhythm/tests/frames.ts +134 -0
- package/archetypes/rhythm/tests/lib.ts +123 -0
- package/archetypes/rhythm/tests/pad.og.ts +41 -0
- package/archetypes/rhythm/tests/pause.og.ts +77 -0
- package/archetypes/rhythm/tests/phone.og.ts +44 -0
- package/archetypes/rhythm/tests/replay.og.ts +27 -0
- package/archetypes/rhythm/tests/timing.og.ts +37 -0
- package/archetypes/rhythm/tools/make-assets.py +383 -0
- package/archetypes/rhythm/tools/oglite.py +285 -0
- package/archetypes/rhythm/tsconfig.json +17 -0
- package/archetypes/roguelike/.origin/setup +14 -0
- package/archetypes/roguelike/LICENSES.md +14 -0
- package/archetypes/roguelike/README.md +256 -0
- package/archetypes/roguelike/assets/ai/foe.ogt +28 -0
- package/archetypes/roguelike/assets/ai/guardian.ogt +26 -0
- package/archetypes/roguelike/assets/audio/bump.wav +0 -0
- package/archetypes/roguelike/assets/audio/drink.wav +0 -0
- package/archetypes/roguelike/assets/audio/fall.wav +0 -0
- package/archetypes/roguelike/assets/audio/hit.wav +0 -0
- package/archetypes/roguelike/assets/audio/hurt.wav +0 -0
- package/archetypes/roguelike/assets/audio/item.wav +0 -0
- package/archetypes/roguelike/assets/audio/kill.wav +0 -0
- package/archetypes/roguelike/assets/audio/pickup.wav +0 -0
- package/archetypes/roguelike/assets/audio/roar.wav +0 -0
- package/archetypes/roguelike/assets/audio/stairs.wav +0 -0
- package/archetypes/roguelike/assets/audio/step.ogt +9 -0
- package/archetypes/roguelike/assets/audio/telegraph.wav +0 -0
- package/archetypes/roguelike/assets/audio/tomb.wav +0 -0
- package/archetypes/roguelike/assets/audio/ui-close.ogt +9 -0
- package/archetypes/roguelike/assets/audio/ui-error.ogt +9 -0
- package/archetypes/roguelike/assets/audio/ui-open.ogt +9 -0
- package/archetypes/roguelike/assets/audio/ui-press.ogt +9 -0
- package/archetypes/roguelike/assets/audio/ui-success.ogt +9 -0
- package/archetypes/roguelike/assets/audio/won.wav +0 -0
- package/archetypes/roguelike/assets/fonts/NotoSansSC-subset.ttf +0 -0
- package/archetypes/roguelike/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
- package/archetypes/roguelike/assets/fonts/OFL.txt +93 -0
- package/archetypes/roguelike/assets/maps/dive.ogt +106 -0
- package/archetypes/roguelike/assets/skins/lampdive/DotGothic16-Regular.ttf +0 -0
- package/archetypes/roguelike/assets/skins/lampdive/DotGothic16-Regular.ttf.ogt +9 -0
- package/archetypes/roguelike/assets/skins/lampdive/LICENSES.md +16 -0
- package/archetypes/roguelike/assets/skins/lampdive/OFL.txt +93 -0
- package/archetypes/roguelike/assets/skins/lampdive/atlas.png +0 -0
- package/archetypes/roguelike/assets/skins/lampdive/atlas.png.ogt +7 -0
- package/archetypes/roguelike/assets/skins/lampdive/icons.png +0 -0
- package/archetypes/roguelike/assets/skins/lampdive/icons.png.ogt +7 -0
- package/archetypes/roguelike/assets/skins/lampdive/skin.ogt +115 -0
- package/archetypes/roguelike/assets/sprites/dive.ogt +50 -0
- package/archetypes/roguelike/assets/sprites/dive.png +0 -0
- package/archetypes/roguelike/assets/sprites/dive.png.ogt +7 -0
- package/archetypes/roguelike/assets/sprites/glow.png +0 -0
- package/archetypes/roguelike/assets/sprites/glow.png.ogt +7 -0
- package/archetypes/roguelike/assets/strings/en.ogt +57 -0
- package/archetypes/roguelike/assets/strings/zh-CN.ogt +57 -0
- package/archetypes/roguelike/assets/tiles/tomb.ogt +31 -0
- package/archetypes/roguelike/assets/tiles/tomb.png +0 -0
- package/archetypes/roguelike/assets/tiles/tomb.png.ogt +7 -0
- package/archetypes/roguelike/gitattributes +22 -0
- package/archetypes/roguelike/host.d.ts +46 -0
- package/archetypes/roguelike/package.json +18 -0
- package/archetypes/roguelike/project.ogt +14 -0
- package/archetypes/roguelike/references/metal/dive.png +0 -0
- package/archetypes/roguelike/references/metal/over.png +0 -0
- package/archetypes/roguelike/references/metal/title.png +0 -0
- package/archetypes/roguelike/src/art.ts +23 -0
- package/archetypes/roguelike/src/components.ts +169 -0
- package/archetypes/roguelike/src/dive.ts +144 -0
- package/archetypes/roguelike/src/foes.ts +174 -0
- package/archetypes/roguelike/src/main.ts +258 -0
- package/archetypes/roguelike/src/systems.ts +620 -0
- package/archetypes/roguelike/src/ui.ts +350 -0
- package/archetypes/roguelike/tests/flow.og.ts +54 -0
- package/archetypes/roguelike/tests/foes.og.ts +45 -0
- package/archetypes/roguelike/tests/frames.og.ts +32 -0
- package/archetypes/roguelike/tests/frames.ts +134 -0
- package/archetypes/roguelike/tests/lib.ts +83 -0
- package/archetypes/roguelike/tests/lose.og.ts +44 -0
- package/archetypes/roguelike/tests/pad.og.ts +54 -0
- package/archetypes/roguelike/tests/pause.og.ts +59 -0
- package/archetypes/roguelike/tests/phone.og.ts +54 -0
- package/archetypes/roguelike/tests/replay.og.ts +24 -0
- package/archetypes/roguelike/tests/win.og.ts +60 -0
- package/archetypes/roguelike/tools/make-assets.py +518 -0
- package/archetypes/roguelike/tools/oglite.py +285 -0
- package/archetypes/roguelike/tsconfig.json +17 -0
- package/archetypes/runner/.origin/setup +14 -0
- package/archetypes/runner/LICENSES.md +10 -0
- package/archetypes/runner/README.md +225 -0
- package/archetypes/runner/assets/audio/coin.wav +0 -0
- package/archetypes/runner/assets/audio/crash.wav +0 -0
- package/archetypes/runner/assets/audio/hold.ogt +9 -0
- package/archetypes/runner/assets/audio/jump.wav +0 -0
- package/archetypes/runner/assets/audio/start.wav +0 -0
- package/archetypes/runner/assets/fonts/OFL.txt +93 -0
- package/archetypes/runner/assets/fonts/ui.ttf +0 -0
- package/archetypes/runner/assets/fonts/ui.ttf.ogt +11 -0
- package/archetypes/runner/assets/maps/far.ogt +25 -0
- package/archetypes/runner/assets/maps/near.ogt +25 -0
- package/archetypes/runner/assets/maps/roofs.ogt +19 -0
- package/archetypes/runner/assets/scenes/main.ogt +35 -0
- package/archetypes/runner/assets/sprites/coin.ogt +11 -0
- package/archetypes/runner/assets/sprites/coin.png +0 -0
- package/archetypes/runner/assets/sprites/coin.png.ogt +7 -0
- package/archetypes/runner/assets/sprites/courier.ogt +32 -0
- package/archetypes/runner/assets/sprites/courier.png +0 -0
- package/archetypes/runner/assets/sprites/courier.png.ogt +7 -0
- package/archetypes/runner/assets/sprites/props.ogt +21 -0
- package/archetypes/runner/assets/sprites/props.png +0 -0
- package/archetypes/runner/assets/sprites/props.png.ogt +7 -0
- package/archetypes/runner/assets/sprites/sky.png +0 -0
- package/archetypes/runner/assets/sprites/sky.png.ogt +7 -0
- package/archetypes/runner/assets/tiles/city.ogt +18 -0
- package/archetypes/runner/assets/tiles/city.png +0 -0
- package/archetypes/runner/assets/tiles/city.png.ogt +7 -0
- package/archetypes/runner/gitattributes +22 -0
- package/archetypes/runner/host.d.ts +46 -0
- package/archetypes/runner/package.json +18 -0
- package/archetypes/runner/project.ogt +18 -0
- package/archetypes/runner/references/metal/frames-coin.png +0 -0
- package/archetypes/runner/references/metal/frames-crash.png +0 -0
- package/archetypes/runner/references/metal/frames-title.png +0 -0
- package/archetypes/runner/src/art.ts +57 -0
- package/archetypes/runner/src/components.ts +94 -0
- package/archetypes/runner/src/main.ts +241 -0
- package/archetypes/runner/src/systems.ts +553 -0
- package/archetypes/runner/tests/coins.og.ts +30 -0
- package/archetypes/runner/tests/flow.og.ts +72 -0
- package/archetypes/runner/tests/frames.og.ts +37 -0
- package/archetypes/runner/tests/frames.ts +134 -0
- package/archetypes/runner/tests/jump.og.ts +44 -0
- package/archetypes/runner/tests/lib.ts +42 -0
- package/archetypes/runner/tests/records.og.ts +43 -0
- package/archetypes/runner/tests/replay.og.ts +36 -0
- package/archetypes/runner/tests/sounds.og.ts +43 -0
- package/archetypes/runner/tests/tune.og.ts +36 -0
- package/archetypes/runner/tools/make-assets.py +603 -0
- package/archetypes/runner/tools/oglite.py +285 -0
- package/archetypes/runner/tsconfig.json +17 -0
- package/archetypes/third-person/.origin/setup +14 -0
- package/archetypes/third-person/LICENSES.md +23 -0
- package/archetypes/third-person/README.md +249 -0
- package/archetypes/third-person/assets/ai/sentinel-east.ogt +69 -0
- package/archetypes/third-person/assets/ai/sentinel-north.ogt +69 -0
- package/archetypes/third-person/assets/ai/sentinel-west.ogt +69 -0
- package/archetypes/third-person/assets/anims/humanoid-clips.glb +0 -0
- package/archetypes/third-person/assets/audio/alarm.wav +0 -0
- package/archetypes/third-person/assets/audio/dawn.wav +0 -0
- package/archetypes/third-person/assets/audio/grab.wav +0 -0
- package/archetypes/third-person/assets/audio/ignite.wav +0 -0
- package/archetypes/third-person/assets/audio/jump.wav +0 -0
- package/archetypes/third-person/assets/audio/night.wav +0 -0
- package/archetypes/third-person/assets/audio/splash.wav +0 -0
- package/archetypes/third-person/assets/audio/step.ogt +9 -0
- package/archetypes/third-person/assets/audio/ui-close.ogt +9 -0
- package/archetypes/third-person/assets/audio/ui-error.ogt +9 -0
- package/archetypes/third-person/assets/audio/ui-open.ogt +9 -0
- package/archetypes/third-person/assets/audio/ui-press.ogt +9 -0
- package/archetypes/third-person/assets/audio/ui-success.ogt +9 -0
- package/archetypes/third-person/assets/audio/vale.wav +0 -0
- package/archetypes/third-person/assets/fonts/NotoSansSC-subset.ttf +0 -0
- package/archetypes/third-person/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
- package/archetypes/third-person/assets/fonts/OFL.txt +93 -0
- package/archetypes/third-person/assets/fx/burst.ogt +25 -0
- package/archetypes/third-person/assets/fx/fire.ogt +24 -0
- package/archetypes/third-person/assets/fx/smoke.ogt +24 -0
- package/archetypes/third-person/assets/fx/splash.ogt +24 -0
- package/archetypes/third-person/assets/luts/teal-orange.cube +4917 -0
- package/archetypes/third-person/assets/models/stout.glb +0 -0
- package/archetypes/third-person/assets/models/strider.glb +0 -0
- package/archetypes/third-person/assets/models/strider.glb.ogt +9 -0
- package/archetypes/third-person/assets/nav/vale.ogt +43 -0
- package/archetypes/third-person/assets/rigs/strider.ogt +6 -0
- package/archetypes/third-person/assets/skins/ember/Cinzel-Bold.ttf +0 -0
- package/archetypes/third-person/assets/skins/ember/Cinzel-Bold.ttf.ogt +9 -0
- package/archetypes/third-person/assets/skins/ember/LICENSES.md +13 -0
- package/archetypes/third-person/assets/skins/ember/Newsreader-Medium.ttf +0 -0
- package/archetypes/third-person/assets/skins/ember/Newsreader-Medium.ttf.ogt +9 -0
- package/archetypes/third-person/assets/skins/ember/OFL.txt +94 -0
- package/archetypes/third-person/assets/skins/ember/atlas.png +0 -0
- package/archetypes/third-person/assets/skins/ember/atlas.png.ogt +7 -0
- package/archetypes/third-person/assets/skins/ember/icons.png +0 -0
- package/archetypes/third-person/assets/skins/ember/icons.png.ogt +7 -0
- package/archetypes/third-person/assets/skins/ember/skin.ogt +109 -0
- package/archetypes/third-person/assets/strings/en.ogt +47 -0
- package/archetypes/third-person/assets/strings/zh-CN.ogt +47 -0
- package/archetypes/third-person/assets/terrain/vale-control.png +0 -0
- package/archetypes/third-person/assets/terrain/vale.ogt +42 -0
- package/archetypes/third-person/assets/terrain/vale.png +0 -0
- package/archetypes/third-person/assets/textures/decals.png +0 -0
- package/archetypes/third-person/assets/textures/flame.png +0 -0
- package/archetypes/third-person/assets/textures/smoke.png +0 -0
- package/archetypes/third-person/assets/textures/spark.png +0 -0
- package/archetypes/third-person/assets/textures/terrain-grass.png +0 -0
- package/archetypes/third-person/assets/textures/terrain-path.png +0 -0
- package/archetypes/third-person/assets/textures/terrain-rock.png +0 -0
- package/archetypes/third-person/assets/textures/terrain-sand.png +0 -0
- package/archetypes/third-person/gitattributes +22 -0
- package/archetypes/third-person/host.d.ts +46 -0
- package/archetypes/third-person/package.json +18 -0
- package/archetypes/third-person/project.ogt +14 -0
- package/archetypes/third-person/references/metal/beacon.png +0 -0
- package/archetypes/third-person/references/metal/dawn.png +0 -0
- package/archetypes/third-person/references/metal/title.png +0 -0
- package/archetypes/third-person/references/webgl2/beacon.png +0 -0
- package/archetypes/third-person/src/anim.ts +87 -0
- package/archetypes/third-person/src/beacons.ts +80 -0
- package/archetypes/third-person/src/components.ts +148 -0
- package/archetypes/third-person/src/hero.ts +293 -0
- package/archetypes/third-person/src/main.ts +164 -0
- package/archetypes/third-person/src/sentinels.ts +159 -0
- package/archetypes/third-person/src/sound.ts +66 -0
- package/archetypes/third-person/src/ui.ts +451 -0
- package/archetypes/third-person/src/world.ts +212 -0
- package/archetypes/third-person/tests/flow.og.ts +70 -0
- package/archetypes/third-person/tests/frames.og.ts +35 -0
- package/archetypes/third-person/tests/frames.ts +134 -0
- package/archetypes/third-person/tests/hitstop.og.ts +26 -0
- package/archetypes/third-person/tests/lib.ts +87 -0
- package/archetypes/third-person/tests/lose.og.ts +44 -0
- package/archetypes/third-person/tests/pause.og.ts +64 -0
- package/archetypes/third-person/tests/phone.og.ts +65 -0
- package/archetypes/third-person/tests/replay.og.ts +32 -0
- package/archetypes/third-person/tests/restart.og.ts +28 -0
- package/archetypes/third-person/tests/sentinels.og.ts +48 -0
- package/archetypes/third-person/tests/win.og.ts +62 -0
- package/archetypes/third-person/tools/make-assets.py +353 -0
- package/archetypes/third-person/tools/oglite.py +285 -0
- package/archetypes/third-person/tsconfig.json +17 -0
- package/archetypes/topdown/.origin/setup +14 -0
- package/archetypes/topdown/LICENSES.md +10 -0
- package/archetypes/topdown/README.md +235 -0
- package/archetypes/topdown/assets/ai/slime.ogt +49 -0
- package/archetypes/topdown/assets/audio/coin.wav +0 -0
- package/archetypes/topdown/assets/audio/door.wav +0 -0
- package/archetypes/topdown/assets/audio/hit.wav +0 -0
- package/archetypes/topdown/assets/audio/hurt.wav +0 -0
- package/archetypes/topdown/assets/audio/key.wav +0 -0
- package/archetypes/topdown/assets/audio/step.ogt +9 -0
- package/archetypes/topdown/assets/fonts/OFL.txt +93 -0
- package/archetypes/topdown/assets/fonts/ui.ttf +0 -0
- package/archetypes/topdown/assets/fonts/ui.ttf.ogt +9 -0
- package/archetypes/topdown/assets/maps/tomb.tmj +2183 -0
- package/archetypes/topdown/assets/sprites/hero.ogt +58 -0
- package/archetypes/topdown/assets/sprites/hero.png +0 -0
- package/archetypes/topdown/assets/sprites/hero.png.ogt +7 -0
- package/archetypes/topdown/assets/sprites/items.ogt +15 -0
- package/archetypes/topdown/assets/sprites/items.png +0 -0
- package/archetypes/topdown/assets/sprites/items.png.ogt +7 -0
- package/archetypes/topdown/assets/sprites/slime.ogt +17 -0
- package/archetypes/topdown/assets/sprites/slime.png +0 -0
- package/archetypes/topdown/assets/sprites/slime.png.ogt +7 -0
- package/archetypes/topdown/assets/tiles/dungeon.ogt +65 -0
- package/archetypes/topdown/assets/tiles/dungeon.png +0 -0
- package/archetypes/topdown/assets/tiles/dungeon.png.ogt +7 -0
- package/archetypes/topdown/gitattributes +22 -0
- package/archetypes/topdown/host.d.ts +46 -0
- package/archetypes/topdown/package.json +18 -0
- package/archetypes/topdown/project.ogt +14 -0
- package/archetypes/topdown/references/metal/crit.png +0 -0
- package/archetypes/topdown/references/metal/dash.png +0 -0
- package/archetypes/topdown/references/metal/east.png +0 -0
- package/archetypes/topdown/references/metal/start.png +0 -0
- package/archetypes/topdown/src/art.ts +48 -0
- package/archetypes/topdown/src/components.ts +128 -0
- package/archetypes/topdown/src/main.ts +275 -0
- package/archetypes/topdown/src/systems.ts +503 -0
- package/archetypes/topdown/tests/ai.og.ts +64 -0
- package/archetypes/topdown/tests/combat.og.ts +72 -0
- package/archetypes/topdown/tests/door.og.ts +62 -0
- package/archetypes/topdown/tests/flee.og.ts +49 -0
- package/archetypes/topdown/tests/frames.og.ts +45 -0
- package/archetypes/topdown/tests/frames.ts +134 -0
- package/archetypes/topdown/tests/lib.ts +71 -0
- package/archetypes/topdown/tests/replay.og.ts +40 -0
- package/archetypes/topdown/tests/walk.og.ts +46 -0
- package/archetypes/topdown/tools/make-assets.py +623 -0
- package/archetypes/topdown/tools/oglite.py +285 -0
- package/archetypes/topdown/tsconfig.json +17 -0
- package/archetypes/tower-defense/.origin/setup +14 -0
- package/archetypes/tower-defense/LICENSES.md +15 -0
- package/archetypes/tower-defense/README.md +240 -0
- package/archetypes/tower-defense/assets/ai/plant.ogt +16 -0
- package/archetypes/tower-defense/assets/audio/clear.wav +0 -0
- package/archetypes/tower-defense/assets/audio/frost.wav +0 -0
- package/archetypes/tower-defense/assets/audio/leak.wav +0 -0
- package/archetypes/tower-defense/assets/audio/lost.wav +0 -0
- package/archetypes/tower-defense/assets/audio/night.wav +0 -0
- package/archetypes/tower-defense/assets/audio/plant.wav +0 -0
- package/archetypes/tower-defense/assets/audio/pop.wav +0 -0
- package/archetypes/tower-defense/assets/audio/thorn.wav +0 -0
- package/archetypes/tower-defense/assets/audio/ui-close.ogt +9 -0
- package/archetypes/tower-defense/assets/audio/ui-error.ogt +9 -0
- package/archetypes/tower-defense/assets/audio/ui-open.ogt +9 -0
- package/archetypes/tower-defense/assets/audio/ui-press.ogt +9 -0
- package/archetypes/tower-defense/assets/audio/ui-success.ogt +9 -0
- package/archetypes/tower-defense/assets/audio/wave.wav +0 -0
- package/archetypes/tower-defense/assets/audio/won.wav +0 -0
- package/archetypes/tower-defense/assets/fonts/NotoSansSC-subset.ttf +0 -0
- package/archetypes/tower-defense/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
- package/archetypes/tower-defense/assets/fonts/OFL.txt +93 -0
- package/archetypes/tower-defense/assets/fx/fireflies.ogt +21 -0
- package/archetypes/tower-defense/assets/fx/pop.ogt +21 -0
- package/archetypes/tower-defense/assets/maps/garden.ogt +91 -0
- package/archetypes/tower-defense/assets/skins/pathguard/Fredoka-SemiBold.ttf +0 -0
- package/archetypes/tower-defense/assets/skins/pathguard/Fredoka-SemiBold.ttf.ogt +9 -0
- package/archetypes/tower-defense/assets/skins/pathguard/LICENSES.md +13 -0
- package/archetypes/tower-defense/assets/skins/pathguard/LilitaOne-Regular.ttf +0 -0
- package/archetypes/tower-defense/assets/skins/pathguard/LilitaOne-Regular.ttf.ogt +9 -0
- package/archetypes/tower-defense/assets/skins/pathguard/OFL.txt +94 -0
- package/archetypes/tower-defense/assets/skins/pathguard/atlas.png +0 -0
- package/archetypes/tower-defense/assets/skins/pathguard/atlas.png.ogt +7 -0
- package/archetypes/tower-defense/assets/skins/pathguard/icons.png +0 -0
- package/archetypes/tower-defense/assets/skins/pathguard/icons.png.ogt +7 -0
- package/archetypes/tower-defense/assets/skins/pathguard/skin.ogt +111 -0
- package/archetypes/tower-defense/assets/sprites/garden.ogt +66 -0
- package/archetypes/tower-defense/assets/sprites/garden.png +0 -0
- package/archetypes/tower-defense/assets/sprites/garden.png.ogt +7 -0
- package/archetypes/tower-defense/assets/sprites/glow.png +0 -0
- package/archetypes/tower-defense/assets/sprites/glow.png.ogt +7 -0
- package/archetypes/tower-defense/assets/sprites/ring.png +0 -0
- package/archetypes/tower-defense/assets/sprites/ring.png.ogt +7 -0
- package/archetypes/tower-defense/assets/sprites/spark.png +0 -0
- package/archetypes/tower-defense/assets/sprites/spark.png.ogt +7 -0
- package/archetypes/tower-defense/assets/strings/en.ogt +47 -0
- package/archetypes/tower-defense/assets/strings/zh-CN.ogt +47 -0
- package/archetypes/tower-defense/assets/tiles/garden.ogt +10 -0
- package/archetypes/tower-defense/assets/tiles/garden.png +0 -0
- package/archetypes/tower-defense/assets/tiles/garden.png.ogt +7 -0
- package/archetypes/tower-defense/gitattributes +22 -0
- package/archetypes/tower-defense/host.d.ts +46 -0
- package/archetypes/tower-defense/package.json +18 -0
- package/archetypes/tower-defense/project.ogt +14 -0
- package/archetypes/tower-defense/references/metal/end.png +0 -0
- package/archetypes/tower-defense/references/metal/title.png +0 -0
- package/archetypes/tower-defense/references/metal/wave.png +0 -0
- package/archetypes/tower-defense/src/art.ts +24 -0
- package/archetypes/tower-defense/src/components.ts +156 -0
- package/archetypes/tower-defense/src/main.ts +253 -0
- package/archetypes/tower-defense/src/systems.ts +658 -0
- package/archetypes/tower-defense/src/ui.ts +382 -0
- package/archetypes/tower-defense/tests/flow.og.ts +56 -0
- package/archetypes/tower-defense/tests/frames.og.ts +31 -0
- package/archetypes/tower-defense/tests/frames.ts +134 -0
- package/archetypes/tower-defense/tests/lib.ts +81 -0
- package/archetypes/tower-defense/tests/lose.og.ts +40 -0
- package/archetypes/tower-defense/tests/maze.og.ts +53 -0
- package/archetypes/tower-defense/tests/pad.og.ts +41 -0
- package/archetypes/tower-defense/tests/pause.og.ts +59 -0
- package/archetypes/tower-defense/tests/phone.og.ts +49 -0
- package/archetypes/tower-defense/tests/replay.og.ts +28 -0
- package/archetypes/tower-defense/tests/win.og.ts +58 -0
- package/archetypes/tower-defense/tools/make-assets.py +640 -0
- package/archetypes/tower-defense/tools/oglite.py +285 -0
- package/archetypes/tower-defense/tsconfig.json +17 -0
- package/bin/create.ts +496 -0
- package/looks/catalogue.json +1871 -0
- package/package.json +31 -4
- package/template/.origin/setup +14 -0
- package/template/LICENSES.md +23 -0
- package/template/README.md +37 -0
- package/template/assets/ai/guard.ogt +48 -0
- package/template/assets/audio/blip.wav +0 -0
- package/template/assets/audio/click.ogt +9 -0
- package/template/assets/fonts/NotoSansSC-Regular-subset.ttf +0 -0
- package/template/assets/fonts/NotoSansSC-Regular-subset.ttf.ogt +12 -0
- package/template/assets/fonts/OFL.txt +93 -0
- package/template/assets/looks/origin-game.ogt +12 -0
- package/template/assets/models/dropship.glb +0 -0
- package/template/assets/models/walker.glb +0 -0
- package/template/assets/nav/yard.ogt +27 -0
- package/template/assets/scenes/main.ogt +34 -0
- package/template/assets/strings/en.ogt +14 -0
- package/template/assets/textures/stone.png +0 -0
- package/template/assets/textures/stone_n.png +0 -0
- package/template/assets/textures/stone_n.png.ogt +7 -0
- package/template/gitattributes +22 -0
- package/template/package.json +18 -0
- package/template/project.ogt +25 -0
- package/template/src/main.ts +246 -0
- package/template/tests/guard.og.ts +67 -0
- package/template/tests/smoke.og.ts +43 -0
- package/template/tsconfig.json +17 -0
package/bin/create.ts
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// `npm create @origingame/game` (and `bun create`): scaffolds the Origin
|
|
3
|
+
// Engine project template (templates/game) into a directory, naming the game.
|
|
4
|
+
//
|
|
5
|
+
// create [dir] [--name "Name"] [--id slug] [--archetype runner|match3|...]
|
|
6
|
+
// [--premise "one line"] [--look <slug>] [--force]
|
|
7
|
+
//
|
|
8
|
+
// The template comes from ./template/ in the published package (prepack:
|
|
9
|
+
// scripts/pack-template.ts) or ../../templates/game in the engine repository;
|
|
10
|
+
// an archetype (a complete small game to start from) from ./archetypes/<name>/
|
|
11
|
+
// or ../../templates/archetypes/<name>/.
|
|
12
|
+
//
|
|
13
|
+
// Every game gets its look, `assets/looks/<id>.ogt`, named by GameDesc.look
|
|
14
|
+
// in the entry: it extends the style catalogue's preset given by --look, or
|
|
15
|
+
// the one whose premise best matches --premise (asked for on a terminal when
|
|
16
|
+
// neither is given), else the template's own. The catalogue is
|
|
17
|
+
// ./looks/catalogue.json in the published package (prepack) or
|
|
18
|
+
// ../../knowledge/looks/catalogue.json in the engine repository.
|
|
19
|
+
|
|
20
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
21
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
22
|
+
import { fileURLToPath } from "node:url";
|
|
23
|
+
|
|
24
|
+
/** Directories of a template copy that are build output, never scaffolded. */
|
|
25
|
+
export const SKIPPED = new Set(["cooked", "dist", "node_modules", "og-out", ".og"]);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Template files stored under another name and renamed in the scaffold: the
|
|
29
|
+
* template's Git attributes route media through LFS in a game's repository,
|
|
30
|
+
* but as `.gitattributes` they would do the same in the engine repository,
|
|
31
|
+
* which stores the template's media as plain blobs.
|
|
32
|
+
*/
|
|
33
|
+
export const RENAMED: ReadonlyMap<string, string> = new Map([["gitattributes", ".gitattributes"]]);
|
|
34
|
+
|
|
35
|
+
export interface CreateOptions {
|
|
36
|
+
readonly dir: string;
|
|
37
|
+
readonly name?: string;
|
|
38
|
+
readonly id?: string;
|
|
39
|
+
readonly force?: boolean;
|
|
40
|
+
/** Start from an archetype (`runner`, `match3`, `topdown`, `tower-defense`, `roguelike`, `idle`, `rhythm`, `third-person`: templates/archetypes/README.md) instead of the project template. */
|
|
41
|
+
readonly archetype?: string;
|
|
42
|
+
/** The template directory; found next to this file when omitted. */
|
|
43
|
+
readonly template?: string;
|
|
44
|
+
/** A style catalogue slug the game's look extends (og-taste §12). */
|
|
45
|
+
readonly look?: string;
|
|
46
|
+
/** The game's premise in a line: the look extends the catalogue style that fits it best, unless `look` is given. */
|
|
47
|
+
readonly premise?: string;
|
|
48
|
+
/** The catalogue file; found next to this file when omitted. */
|
|
49
|
+
readonly catalogue?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The game's look as written. */
|
|
53
|
+
export interface CreatedLook {
|
|
54
|
+
/** The look file, relative to the game (`assets/looks/<id>.ogt`). */
|
|
55
|
+
readonly file: string;
|
|
56
|
+
/** Its asset id, as GameDesc.look names it (`looks/<id>.ogt`). */
|
|
57
|
+
readonly id: string;
|
|
58
|
+
/** The catalogue slug it extends; null for a look that extends no preset. */
|
|
59
|
+
readonly extends: string | null;
|
|
60
|
+
/** How the preset was chosen. */
|
|
61
|
+
readonly chosen: "flag" | "premise" | "template" | "none";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface Created {
|
|
65
|
+
readonly dir: string;
|
|
66
|
+
readonly name: string;
|
|
67
|
+
readonly id: string;
|
|
68
|
+
readonly files: readonly string[];
|
|
69
|
+
readonly look: CreatedLook;
|
|
70
|
+
/** What the game's author should know, such as reference frames a look will move. */
|
|
71
|
+
readonly notes: readonly string[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** A style catalogue entry: the fields create reads (packages/knowledge/looks/catalogue.json). */
|
|
75
|
+
export interface Style {
|
|
76
|
+
readonly slug: string;
|
|
77
|
+
readonly name: string;
|
|
78
|
+
readonly category: string;
|
|
79
|
+
readonly descriptor: string;
|
|
80
|
+
readonly premise: Readonly<Record<string, string>>;
|
|
81
|
+
readonly look: { readonly presetReady: boolean; readonly support: string; readonly missing: readonly string[] };
|
|
82
|
+
readonly skin: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The style catalogue this copy of the package reads. */
|
|
86
|
+
export function catalogueFile(): string {
|
|
87
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
88
|
+
for (const candidate of [join(here, "..", "looks", "catalogue.json"), join(here, "..", "..", "knowledge", "looks", "catalogue.json")]) {
|
|
89
|
+
if (existsSync(candidate)) return candidate;
|
|
90
|
+
}
|
|
91
|
+
throw new Error(`no style catalogue next to ${here}: expected ../looks/catalogue.json (published package) or ../../knowledge/looks/catalogue.json (engine repository)`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function readCatalogue(file = catalogueFile()): Style[] {
|
|
95
|
+
return (JSON.parse(readFileSync(file, "utf8")) as { styles: Style[] }).styles;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const STOP = new Set(["the", "and", "for", "with", "about", "into", "from", "that", "this", "game", "games", "player", "players", "where", "who", "your", "you", "its", "set", "lot", "very", "like", "one", "two", "all", "any", "out", "their", "them", "has", "have", "are", "was", "but", "not", "own"]);
|
|
99
|
+
const SPELLING: Readonly<Record<string, string>> = { cozy: "cosy", color: "colour", colors: "colours", gray: "grey", scifi: "sci", "sci-fi": "sci", watercolour: "watercolor", "8-bit": "8bit", "16-bit": "16bit", "1-bit": "1bit" };
|
|
100
|
+
|
|
101
|
+
/** Lowercase words, spelling unified and a plural's s dropped: `Cozy Platformers` -> cosy, platformer. */
|
|
102
|
+
export function words(text: string): string[] {
|
|
103
|
+
const spelt = (w: string) => SPELLING[w] ?? w;
|
|
104
|
+
return (text.toLowerCase().match(/[a-z0-9]+(?:-[a-z0-9]+)*/g) ?? [])
|
|
105
|
+
.flatMap((w) => (SPELLING[w] ? [SPELLING[w]!] : w.includes("-") ? [w, ...w.split("-").map(spelt)] : [spelt(w)]))
|
|
106
|
+
.map((w) => (w.length > 4 && w.endsWith("s") && !w.endsWith("ss") ? w.slice(0, -1) : w))
|
|
107
|
+
.filter((w) => w.length >= 3 && !STOP.has(w));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The catalogue style whose premise fits a game's premise best: each word of
|
|
112
|
+
* the premise found in a style's genre counts 3, in its mood 2, in its era
|
|
113
|
+
* or audience 1, in its name or descriptor 1. Ties go to the style whose
|
|
114
|
+
* look the engine draws whole (support `full`), then to catalogue order.
|
|
115
|
+
* Null when no word matches any style. Only styles with a preset are chosen.
|
|
116
|
+
*/
|
|
117
|
+
export function pickStyle(premise: string, styles: readonly Style[]): { style: Style; score: number } | null {
|
|
118
|
+
const asked = new Set(words(premise));
|
|
119
|
+
if (asked.size === 0) return null;
|
|
120
|
+
const weights: [(s: Style) => string, number][] = [
|
|
121
|
+
[(s) => s.premise.genre ?? "", 3],
|
|
122
|
+
[(s) => s.premise.mood ?? "", 2],
|
|
123
|
+
[(s) => s.premise.era ?? "", 1],
|
|
124
|
+
[(s) => s.premise.audience ?? "", 1],
|
|
125
|
+
[(s) => `${s.name} ${s.descriptor}`, 1],
|
|
126
|
+
];
|
|
127
|
+
let best: { style: Style; score: number; full: boolean } | null = null;
|
|
128
|
+
for (const style of styles) {
|
|
129
|
+
if (!style.look.presetReady) continue;
|
|
130
|
+
let score = 0;
|
|
131
|
+
for (const [field, weight] of weights) {
|
|
132
|
+
const have = new Set(words(field(style)));
|
|
133
|
+
for (const w of asked) if (have.has(w)) score += weight;
|
|
134
|
+
}
|
|
135
|
+
const full = style.look.support === "full";
|
|
136
|
+
if (score > 0 && (!best || score > best.score || (score === best.score && full && !best.full))) best = { style, score, full };
|
|
137
|
+
}
|
|
138
|
+
return best && { style: best.style, score: best.score };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** `My Game!` -> `my-game`. */
|
|
142
|
+
export function slug(name: string): string {
|
|
143
|
+
return name
|
|
144
|
+
.normalize("NFKD")
|
|
145
|
+
.replace(/[̀-ͯ]/g, "")
|
|
146
|
+
.toLowerCase()
|
|
147
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
148
|
+
.replace(/^-+|-+$/g, "");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** `my-game` -> `My Game`. */
|
|
152
|
+
function title(id: string): string {
|
|
153
|
+
return id
|
|
154
|
+
.split(/[-_\s]+/)
|
|
155
|
+
.filter(Boolean)
|
|
156
|
+
.map((w) => w[0]!.toUpperCase() + w.slice(1))
|
|
157
|
+
.join(" ");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** The template this copy of the package scaffolds. */
|
|
161
|
+
export function templateDir(archetype?: string): string {
|
|
162
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
163
|
+
if (archetype !== undefined) {
|
|
164
|
+
const roots = [join(here, "..", "archetypes"), join(here, "..", "..", "..", "templates", "archetypes")];
|
|
165
|
+
for (const root of roots) {
|
|
166
|
+
if (existsSync(join(root, archetype, "project.ogt"))) return join(root, archetype);
|
|
167
|
+
}
|
|
168
|
+
const known = roots.filter(existsSync).flatMap((r) => readdirSync(r).filter((d) => existsSync(join(r, d, "project.ogt"))));
|
|
169
|
+
throw new Error(`no archetype '${archetype}': choose one of ${[...new Set(known)].sort().join(", ") || "(none shipped)"}`);
|
|
170
|
+
}
|
|
171
|
+
for (const candidate of [join(here, "..", "template"), join(here, "..", "..", "..", "templates", "game")]) {
|
|
172
|
+
if (existsSync(join(candidate, "project.ogt"))) return candidate;
|
|
173
|
+
}
|
|
174
|
+
throw new Error(`no project template next to ${here}: expected ../template (published package) or ../../../templates/game (engine repository)`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function ogtString(value: string): string {
|
|
178
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n")}"`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Replace the value of a top-level `key "..."` line of an .ogt document. */
|
|
182
|
+
function setOgt(text: string, key: string, value: string): string {
|
|
183
|
+
const line = new RegExp(`^${key}[ \\t]+"(?:[^"\\\\]|\\\\.)*"[ \\t]*$`, "m");
|
|
184
|
+
if (!line.test(text)) throw new Error(`the template's project.ogt has no \`${key} "..."\` line`);
|
|
185
|
+
return text.replace(line, `${key} ${ogtString(value)}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Every file under `root`, relative, skipping build output. */
|
|
189
|
+
function files(root: string, at = root): string[] {
|
|
190
|
+
const out: string[] = [];
|
|
191
|
+
for (const entry of readdirSync(at).sort()) {
|
|
192
|
+
const path = join(at, entry);
|
|
193
|
+
if (statSync(path).isDirectory()) {
|
|
194
|
+
if (SKIPPED.has(entry) && at === root) continue;
|
|
195
|
+
out.push(...files(root, path));
|
|
196
|
+
} else out.push(relative(root, path));
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** The entry file a project manifest names (`entry "src/main.ts"`). */
|
|
202
|
+
function entryOf(dir: string): string | undefined {
|
|
203
|
+
const m = /^entry[ \t]+"([^"]+)"/m.exec(readFileSync(join(dir, "project.ogt"), "utf8"));
|
|
204
|
+
return m?.[1];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const LOOK_KEY = /^([ \t]*)look:[ \t]*"looks\/([^"]+)\.ogt",?[ \t]*$/m;
|
|
208
|
+
|
|
209
|
+
/** A look file's `extends` and its lines after `---` without the header comment, `name` and `extends`. */
|
|
210
|
+
function lookBody(text: string): { extends: string | null; body: string[] } {
|
|
211
|
+
const lines = text.split("\n");
|
|
212
|
+
const at = lines.indexOf("---");
|
|
213
|
+
const rest = at < 0 ? lines : lines.slice(at + 1);
|
|
214
|
+
const ext = /^extends[ \t]+"([^"]+)"/m.exec(rest.join("\n"))?.[1] ?? null;
|
|
215
|
+
// The header comment goes (create writes its own); comments inside stay.
|
|
216
|
+
let first = 0;
|
|
217
|
+
while (first < rest.length && (rest[first]!.trim() === "" || rest[first]!.startsWith("#"))) first++;
|
|
218
|
+
const body = rest.slice(first).filter((l) => !/^(name|extends)[ \t]/.test(l));
|
|
219
|
+
while (body.length > 0 && body[body.length - 1]!.trim() === "") body.pop();
|
|
220
|
+
return { extends: ext, body };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** The game's look file. */
|
|
224
|
+
function lookText(name: string, style: Style | undefined, slug: string | null, id: string, body: readonly string[]): string {
|
|
225
|
+
const head = [
|
|
226
|
+
"type look",
|
|
227
|
+
"version 1",
|
|
228
|
+
"---",
|
|
229
|
+
`# The look of ${name} (og-taste §12): the frame's art direction as data.`,
|
|
230
|
+
"# GameDesc.look in the entry names it; it is applied after the first scene",
|
|
231
|
+
"# spawns and before start runs, so start may still change any of it.",
|
|
232
|
+
];
|
|
233
|
+
if (slug && style) {
|
|
234
|
+
head.push(
|
|
235
|
+
`# It extends the style catalogue's ${slug} preset (${style.name}),`,
|
|
236
|
+
style.look.support === "full" ? "# whose primitives all draw today." : `# support ${style.look.support}: ${style.look.missing.join("; ")}.`,
|
|
237
|
+
`# The style's UI skin pack is ${style.skin}: copy templates/ui-kit/assets/skins/${style.skin}`,
|
|
238
|
+
`# to assets/skins/${id}/ and add \`skin "skins/${id}/skin.ogt"\` to dress the UI.`,
|
|
239
|
+
);
|
|
240
|
+
} else if (slug) head.push(`# It extends ${slug}.`);
|
|
241
|
+
else head.push("# It extends no preset yet: the frame is the engine's defaults plus the lines below.");
|
|
242
|
+
head.push(
|
|
243
|
+
"# A block below (RenderSettings, PostEffects, Stylise, MaterialStyle, Fog,",
|
|
244
|
+
"# Sky, Environment) wins over the preset field by field. For another",
|
|
245
|
+
"# style, set `extends` to another catalogue slug and run og cook.",
|
|
246
|
+
`name ${ogtString(name)}`,
|
|
247
|
+
);
|
|
248
|
+
if (slug) head.push(`extends ${ogtString(slug)}`);
|
|
249
|
+
return `${[...head, ...body].join("\n")}\n`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** The README section that tells the game's author where the look is and how to change it. */
|
|
253
|
+
function lookReadme(look: CreatedLook, style: Style | undefined, entry: string, references: boolean): string {
|
|
254
|
+
const how = look.chosen === "premise" ? ", chosen from the game's premise" : look.chosen === "flag" ? ", chosen with `--look`" : "";
|
|
255
|
+
const lines = [
|
|
256
|
+
"",
|
|
257
|
+
"## The look",
|
|
258
|
+
"",
|
|
259
|
+
"The game's art direction is data, in one file a reader can diff:",
|
|
260
|
+
`\`${look.file}\` (an \`.ogt\` of \`type look\`), named by`,
|
|
261
|
+
`\`look: "${look.id}"\` in the \`og.game({...})\` of \`${entry}\`. It is applied`,
|
|
262
|
+
"after the first scene spawns and before `start` runs, and sets tone",
|
|
263
|
+
"mapping and exposure, the post stack, the stylisation (`Stylise`),",
|
|
264
|
+
"material defaults (`MaterialStyle`: toon, outlines, flat shading), fog,",
|
|
265
|
+
"sky, the environment map and the UI skin.",
|
|
266
|
+
"",
|
|
267
|
+
];
|
|
268
|
+
if (look.extends && style) {
|
|
269
|
+
lines.push(`It extends \`${look.extends}\`${how}: "${style.name}" in the style`, `catalogue. ${style.descriptor} Its UI skin pack is \`${style.skin}\`.`, "");
|
|
270
|
+
} else if (look.extends) lines.push(`It extends \`${look.extends}\`${how}.`, "");
|
|
271
|
+
else lines.push("It extends no preset yet: the frame is the engine's defaults plus what", "the file sets.", "");
|
|
272
|
+
lines.push(
|
|
273
|
+
"To change it:",
|
|
274
|
+
"",
|
|
275
|
+
"- **Another style**: set `extends \"<slug>\"` to another entry of the style",
|
|
276
|
+
" catalogue (the og-taste skill's §12 lists all 37 with the premises each",
|
|
277
|
+
" fits and three checks to hold the frames to), then `og cook`.",
|
|
278
|
+
"- **Tune it**: add a block after `extends`; a field written there wins",
|
|
279
|
+
" over the preset's, field by field:",
|
|
280
|
+
"",
|
|
281
|
+
" ```text",
|
|
282
|
+
" RenderSettings {",
|
|
283
|
+
" toneMapping agx",
|
|
284
|
+
" exposure 1.1",
|
|
285
|
+
" }",
|
|
286
|
+
" ```",
|
|
287
|
+
"",
|
|
288
|
+
"- **Switch at a tick** (a flashback, an area's mood): `og.load.look` a",
|
|
289
|
+
" second look file and `og.render.applyLook(world, look)`.",
|
|
290
|
+
"- **Check it**: `og run --headless --commands \"1:screenshot:look.png;1.1:quit\"`",
|
|
291
|
+
" and read the frame against the style's checks.",
|
|
292
|
+
);
|
|
293
|
+
if (references) {
|
|
294
|
+
lines.push(
|
|
295
|
+
"",
|
|
296
|
+
"The frames in `references/` show the look they were recorded with: after",
|
|
297
|
+
"changing the look, record them again with `OG_FX_CAPTURE=1 og test .` and",
|
|
298
|
+
"read the new frames before committing them.",
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
return `${lines.join("\n")}\n`;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Scaffold the template into `options.dir`. Throws with the fix on refusal. */
|
|
305
|
+
export function create(options: CreateOptions): Created {
|
|
306
|
+
const dir = resolve(options.dir);
|
|
307
|
+
const id = options.id ?? slug(options.name ?? basename(dir));
|
|
308
|
+
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(id)) {
|
|
309
|
+
throw new Error(`'${id}' is not a game id: use lowercase letters, digits and single hyphens, as \`--id my-game\``);
|
|
310
|
+
}
|
|
311
|
+
const name = options.name ?? title(id);
|
|
312
|
+
if (existsSync(dir)) {
|
|
313
|
+
if (!statSync(dir).isDirectory()) throw new Error(`${dir} is a file; pick another directory`);
|
|
314
|
+
if (readdirSync(dir).length > 0 && !options.force) {
|
|
315
|
+
throw new Error(`${dir} is not empty; pick an empty directory, or pass --force to write the template over it`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const choice = chooseStyle(options);
|
|
319
|
+
const template = options.template ?? templateDir(options.archetype);
|
|
320
|
+
const list = files(template);
|
|
321
|
+
const written: string[] = [];
|
|
322
|
+
mkdirSync(dir, { recursive: true });
|
|
323
|
+
for (const file of list) {
|
|
324
|
+
const to = RENAMED.get(file) ?? file;
|
|
325
|
+
mkdirSync(dirname(join(dir, to)), { recursive: true });
|
|
326
|
+
cpSync(join(template, file), join(dir, to));
|
|
327
|
+
written.push(to);
|
|
328
|
+
}
|
|
329
|
+
const manifest = join(dir, "project.ogt");
|
|
330
|
+
writeFileSync(manifest, setOgt(setOgt(readFileSync(manifest, "utf8"), "name", name), "id", id));
|
|
331
|
+
const pkgPath = join(dir, "package.json");
|
|
332
|
+
if (existsSync(pkgPath)) {
|
|
333
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8")) as Record<string, unknown>;
|
|
334
|
+
pkg.name = id;
|
|
335
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
336
|
+
}
|
|
337
|
+
const { look, notes } = writeLook(dir, name, id, choice, written);
|
|
338
|
+
return { dir, name, id, files: written, look, notes };
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* The game's look: `assets/looks/<id>.ogt`, carrying the template's own look
|
|
343
|
+
* (the file its entry names) with the preset `options.look` or the premise
|
|
344
|
+
* chose, and the entry's GameDesc.look pointed at it (inserted after
|
|
345
|
+
* `og.game({` when the template names none).
|
|
346
|
+
*/
|
|
347
|
+
/** The preset `--look` names or the premise fits; throws for a slug the catalogue has no preset for. */
|
|
348
|
+
function chooseStyle(options: CreateOptions): { styles: Style[]; style: Style | undefined; chosen: CreatedLook["chosen"]; notes: string[] } {
|
|
349
|
+
const styles = readCatalogue(options.catalogue);
|
|
350
|
+
if (options.look !== undefined) {
|
|
351
|
+
const style = styles.find((s) => s.slug === options.look);
|
|
352
|
+
if (!style || !style.look.presetReady) {
|
|
353
|
+
throw new Error(`no look preset '${options.look}': choose one of the style catalogue's slugs (og-taste §12): ${styles.filter((s) => s.look.presetReady).map((s) => s.slug).join(", ")}`);
|
|
354
|
+
}
|
|
355
|
+
return { styles, style, chosen: "flag", notes: [] };
|
|
356
|
+
}
|
|
357
|
+
if (options.premise !== undefined && options.premise.trim() !== "") {
|
|
358
|
+
const pick = pickStyle(options.premise, styles);
|
|
359
|
+
if (pick) return { styles, style: pick.style, chosen: "premise", notes: [] };
|
|
360
|
+
return { styles, style: undefined, chosen: "none", notes: [`no catalogue style matched the premise "${options.premise}"; the look keeps the template's (og-taste §1 chooses one by genre, mood, era and audience: pass --look <slug>)`] };
|
|
361
|
+
}
|
|
362
|
+
return { styles, style: undefined, chosen: "none", notes: [] };
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function writeLook(dir: string, name: string, id: string, choice: ReturnType<typeof chooseStyle>, written: string[]): { look: CreatedLook; notes: string[] } {
|
|
366
|
+
const { styles, notes } = choice;
|
|
367
|
+
let { style, chosen } = choice;
|
|
368
|
+
|
|
369
|
+
const entry = entryOf(dir) ?? "src/main.ts";
|
|
370
|
+
const entryPath = join(dir, entry);
|
|
371
|
+
const source = existsSync(entryPath) ? readFileSync(entryPath, "utf8") : undefined;
|
|
372
|
+
const named = source === undefined ? undefined : LOOK_KEY.exec(source);
|
|
373
|
+
const file = `assets/looks/${id}.ogt`;
|
|
374
|
+
const lookId = `looks/${id}.ogt`;
|
|
375
|
+
let base: { extends: string | null; body: string[] } = { extends: null, body: [] };
|
|
376
|
+
if (named) {
|
|
377
|
+
const old = join(dir, "assets", "looks", `${named[2]}.ogt`);
|
|
378
|
+
if (existsSync(old)) {
|
|
379
|
+
base = lookBody(readFileSync(old, "utf8"));
|
|
380
|
+
if (`assets/looks/${named[2]}.ogt` !== file) {
|
|
381
|
+
rmSync(old);
|
|
382
|
+
const listed = written.indexOf(`assets/looks/${named[2]}.ogt`);
|
|
383
|
+
if (listed >= 0) written.splice(listed, 1);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
let slug: string | null = style?.slug ?? base.extends;
|
|
388
|
+
if (!style && slug) {
|
|
389
|
+
style = styles.find((s) => s.slug === slug);
|
|
390
|
+
if (style) chosen = "template";
|
|
391
|
+
}
|
|
392
|
+
mkdirSync(join(dir, "assets", "looks"), { recursive: true });
|
|
393
|
+
writeFileSync(join(dir, file), lookText(name, style, slug, id, base.body));
|
|
394
|
+
if (!written.includes(file)) written.push(file);
|
|
395
|
+
|
|
396
|
+
if (source !== undefined) {
|
|
397
|
+
let next: string | undefined;
|
|
398
|
+
if (named) next = source.replace(LOOK_KEY, `${named[1]}look: "${lookId}",`);
|
|
399
|
+
else {
|
|
400
|
+
const game = /^([ \t]*)export default og\.game\(\{[ \t]*$/m.exec(source);
|
|
401
|
+
if (game) {
|
|
402
|
+
const at = game.index + game[0].length;
|
|
403
|
+
next = `${source.slice(0, at)}\n${game[1]} // The art direction as data (assets/${lookId}; og-taste §12).\n${game[1]} look: "${lookId}",${source.slice(at)}`;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (next !== undefined) writeFileSync(entryPath, next);
|
|
407
|
+
else notes.push(`${entry} has no \`export default og.game({\` line: add \`look: "${lookId}"\` to the game's desc yourself`);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const references = existsSync(join(dir, "references"));
|
|
411
|
+
if (references && slug !== base.extends) {
|
|
412
|
+
notes.push(`the frames in references/ show the archetype's own look; with ${slug} they will differ: record them again with \`OG_FX_CAPTURE=1 og test .\``);
|
|
413
|
+
}
|
|
414
|
+
if (style && style.look.support !== "full") notes.push(`${style.slug} is \`${style.look.support}\`: ${style.look.missing.join("; ")} (og-taste §12)`);
|
|
415
|
+
const look: CreatedLook = { file, id: lookId, extends: slug, chosen };
|
|
416
|
+
const readme = join(dir, "README.md");
|
|
417
|
+
const section = lookReadme(look, style, entry, references);
|
|
418
|
+
writeFileSync(readme, existsSync(readme) ? `${readFileSync(readme, "utf8").replace(/\n*$/, "\n")}${section}` : `# ${name}\n${section}`);
|
|
419
|
+
if (!written.includes("README.md")) written.push("README.md");
|
|
420
|
+
return { look, notes };
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const USAGE = `usage: create [dir] [--name "Name"] [--id slug] [--archetype name] [--premise "one line"] [--look slug] [--force]
|
|
424
|
+
|
|
425
|
+
Scaffolds an Origin Engine game into dir (default: ./origin-game).
|
|
426
|
+
--name the game's display name (default: from the id or the directory)
|
|
427
|
+
--id the game's id, lowercase-hyphen (default: from the name)
|
|
428
|
+
--archetype start from a complete archetype game (runner, match3, topdown, tower-defense, roguelike, idle, rhythm, third-person) instead of the template
|
|
429
|
+
--premise the game in one line (genre, mood, setting, audience): its look extends the style catalogue's best match (asked for on a terminal when neither this nor --look is given)
|
|
430
|
+
--look the style catalogue slug the look extends (og-taste §12), such as anime-cel-3d or 16bit-pixel
|
|
431
|
+
--no-prompt never ask for the premise
|
|
432
|
+
--force write into a directory that is not empty`;
|
|
433
|
+
|
|
434
|
+
function main(argv: string[]): number {
|
|
435
|
+
let dir: string | undefined;
|
|
436
|
+
let name: string | undefined;
|
|
437
|
+
let id: string | undefined;
|
|
438
|
+
let force = false;
|
|
439
|
+
let archetype: string | undefined;
|
|
440
|
+
let premise: string | undefined;
|
|
441
|
+
let look: string | undefined;
|
|
442
|
+
let ask = true;
|
|
443
|
+
for (let i = 0; i < argv.length; i++) {
|
|
444
|
+
const a = argv[i]!;
|
|
445
|
+
const value = () => {
|
|
446
|
+
const v = argv[++i];
|
|
447
|
+
if (v === undefined) throw new Error(`${a} needs a value. ${USAGE}`);
|
|
448
|
+
return v;
|
|
449
|
+
};
|
|
450
|
+
if (a === "--name") name = value();
|
|
451
|
+
else if (a === "--id") id = value();
|
|
452
|
+
else if (a === "--force") force = true;
|
|
453
|
+
else if (a === "--archetype") archetype = value();
|
|
454
|
+
else if (a === "--premise") premise = value();
|
|
455
|
+
else if (a === "--look") look = value();
|
|
456
|
+
else if (a === "--no-prompt") ask = false;
|
|
457
|
+
else if (a === "-h" || a === "--help") {
|
|
458
|
+
console.log(USAGE);
|
|
459
|
+
return 0;
|
|
460
|
+
} else if (a.startsWith("-")) throw new Error(`unknown option ${a}. ${USAGE}`);
|
|
461
|
+
else if (dir === undefined) dir = a;
|
|
462
|
+
else throw new Error(`one directory only, got '${dir}' and '${a}'. ${USAGE}`);
|
|
463
|
+
}
|
|
464
|
+
if (ask && premise === undefined && look === undefined && process.stdin.isTTY && process.stdout.isTTY && typeof globalThis.prompt === "function") {
|
|
465
|
+
premise = globalThis.prompt("What is the game, in one line (genre, mood, setting)? It picks the look; Enter keeps the template's:") ?? undefined;
|
|
466
|
+
}
|
|
467
|
+
const made = create({
|
|
468
|
+
dir: dir ?? (id ?? (name ? slug(name) : "origin-game")),
|
|
469
|
+
...(name ? { name } : {}),
|
|
470
|
+
...(id ? { id } : {}),
|
|
471
|
+
...(archetype ? { archetype } : {}),
|
|
472
|
+
...(premise ? { premise } : {}),
|
|
473
|
+
...(look ? { look } : {}),
|
|
474
|
+
force,
|
|
475
|
+
});
|
|
476
|
+
const shown = relative(process.cwd(), made.dir) || ".";
|
|
477
|
+
const style = made.look.extends ? `extends ${made.look.extends}${made.look.chosen === "premise" ? " (from the premise)" : made.look.chosen === "flag" ? " (--look)" : ""}` : "extends no preset";
|
|
478
|
+
console.log(`Created ${made.name} (${made.id}) in ${shown}: ${made.files.length} files.
|
|
479
|
+
Look: ${made.look.file}, ${style}; README.md says how to change it.${made.notes.map((n) => `\nNote: ${n}`).join("")}
|
|
480
|
+
|
|
481
|
+
Next:
|
|
482
|
+
cd ${shown}
|
|
483
|
+
bun install
|
|
484
|
+
og cook
|
|
485
|
+
og run .`);
|
|
486
|
+
return 0;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (import.meta.main) {
|
|
490
|
+
try {
|
|
491
|
+
process.exit(main(process.argv.slice(2)));
|
|
492
|
+
} catch (e) {
|
|
493
|
+
console.error(`create: ${e instanceof Error ? e.message : String(e)}`);
|
|
494
|
+
process.exit(1);
|
|
495
|
+
}
|
|
496
|
+
}
|