mui-z/effectivenovelcore
This is novel text parse and provide display event stream package.
About
This is novel engine.
This effectively helps to display the characters of the novel.
This library doesn't include UI layer. This only provides parse and output stream display event. (Example of use: EffectiveNovelReader)
Requires Swift 6. EFNovelController is @MainActor; create and call it from the main actor (typical for UI).
Architecture (Clean Architecture)
- Domain: script entities (
EFNovelScript,DisplayEvent), parsing, validation, and pure playback rules (NovelState,NovelPlaybackState,NovelPlaybackReducer). - Application: stateless use cases only — e.g.
ValidateScriptUseCase(immutable collaborators viainit, no long-lived mutable fields). - Interface adapters:
EFNovelController+NovelPlaybackSessionhold playback runtime state and the async loop; domain rules stay inNovelPlaybackReducer. Combine:AnyPublisher<DisplayEvent, Never>.
Also, this lib is not optimized novel game, because this doesn't have if functioned, macro, subroutine.
If you use it for such a purpose, please parse it each time on the application side to use it.
Demo
demo: EffectiveNovelReader
<img src=https://user-images.githubusercontent.com/93278577/199856220-e8560b14-5e93-431d-8afc-3fe454690d46.gif width=300 />
Syntax
Use tags to control how they are displayed.
This syntax is based on Tyranoscript.
Syntax Tags
Tags must be enclosed in ``.
When commenting out, put # at the beginning. If you want to use #, write \\#
| tag | DisplayEvent | description | |----------------------------|-----------------------------------|-----------------------------------------------------------------------------| | n | .newline | newline | | tw | .tapWait | tap wait | | twn | .tapWaitAndNewline | tap wait and newline | | cl | .clear | clear | | sleep duration=xxxx | .sleep(duration: Double) | sleep for the specified time. duration unit is milliseconds. | | delay speed=xxxx | .delay(speed: Double) | change delay character displayed speed. speed unit is milliseconds. | | setDefaultDelay speed=xxxx | .setDefaultDelay(speed: Double) | change default delay character displayed speed. speed unit is milliseconds. | | resetDelay | .resetDelay | reset delay speed | | e | .end | stop script novel end point |
Example Novel Script
# Sample Script
tap waiting and newline[twn]
[cl] cleared text.
very fast stream after this text[delay speed=2][n]
displaying!!!!!!
[resetDelay]reset delay speed.[n]
end. [e]Usage
State Flow
stateDiagram-v2
direction LR
[*] --> loadWait
loadWait --> prepare: load
prepare --> running: start
running --> loadWait: finish
running --> pause: pause
pause --> running: resume
running --> loadWait: interrupt
pause --> loadWait: interruptSample Code
// 1. On the main actor, create `EFNovelController`.
let controller = EFNovelController()
// 2. Load raw novel text
let result: ValidationResult<EFNovelScript, [ValidationError]> = controller.load(raw: rawText)
let novelScript: EFNovelScript
switch result {
case .valid(let script):
novelScript = script
case .invalid(let errors):
print(errors)
// handle error.
}
// 3. Start and listen to the stream
controller.start(script: novelScript)
.sink { event in
switch event {
case .character(let char):
displayCharacter(char)
// handle other commands
default:
break
}
}
.store(in: &cancellables)
// (4.) Show text until the next wait tag
controller.showTextUntilWaitTag()
// (5.) Pause stream
controller.pause()
// (6.) Resume (optionally `controller.resume(at: 100)`)
controller.resume()
// (7.) Interrupt
controller.interrupt()Examples
- [x] CUI novel reader —
Examples/EffectiveNovelCLI(macOS terminal, Enter = tap) - [x] iOS novel reader
- EffectiveNovelReader — bundled example under Examples/EffectiveNovelReader targets iOS 17+ (@Observable / Observation)
Todo
- [ ] value input
- [x] novel text validator
- [x] rearchitecture
- [ ] Swift-DocC
- [x] comment out syntax
LICENSE
EffectiveNovelCore is licensed under the MIT License
Package Metadata
Repository: mui-z/effectivenovelcore
Default branch: main
README: README.md