De volledige Questwright-documentatie
Alle 12 handleidingen op één pagina · Laatst bijgewerkt 12 jul 2026
Aan de slag
Questwright compileert quests die als eenvoudige tekstbestanden geschreven zijn tot speelbare MetaHuman-dialoogscènes, inclusief voice-over, lip-sync, staging, camera’s, doelen en journaal. Deze gids brengt je van een verse installatie naar een pratende NPC.
Vereisten
| Vereiste | Waarde |
|---|---|
| Unreal Engine | 5.6 – 5.8 |
| Lip-sync bakken | MetaHuman-plugin + DX12 (optioneel; zie hieronder) |
| Personages | MetaHumans voor de volledige gezichtsdemonstratie; anders elk personage met een skeletal mesh |
| Voice-over | Optioneel: gratis lokale TTS-server, ElevenLabs (je eigen sleutel) of je eigen WAV-bestanden |
| Projecttype | C++ of alleen Blueprint |
Twee dingen zijn het waard om te weten voordat je begint:
- MetaHumans zijn optioneel. Dialogen, quests, staging, camera’s, het journaal en opslaan werken met elk personage met een skeletal mesh. De MetaHuman-pipeline verzorgt alleen de gebakken lip-sync en de gelaagde gezichtsanimatie; zonder die pipeline valt de build netjes terug op een neutraal gezicht.
- Er wordt niets meegeleverd en er belt niets naar huis. Spraaksynthese en machinevertaling gebruiken je eigen diensten en sleutels; met je eigen WAV-bestanden draait de plugin volledig offline.
Installeren vanaf Fab
- Open de Questwright-productpagina op Fab en voeg de plugin toe aan je bibliotheek.
- Zoek hem in de Epic Games Launcher onder Library → Fab Library en klik op Install to Engine.
- Open je project, ga naar Edit → Plugins, zoek Questwright, vink Enabled aan en herstart de editor.
Voor source builds of CI zet je de plugin in plaats daarvan aan in de .uproject:
{
"Plugins": [
{ "Name": "Questwright", "Enabled": true }
]
}
Projectinrichting met één klik
Open Tools → Quest Studio. De Studio is het ene venster van waaruit alles wordt aangestuurd; de rest van de documentatie neemt je er in detail door mee.

Klik op het tandwiel Global Setup in de bibliotheekbalk. Het koppelt de Blueprints van je Player pawn en PlayerController aan de vereiste Questwright-componenten: interactie, dialoogclient, quest-HUD. Eén klik, idempotent, omkeerbaar.

Je personages casten
Open het tabblad Cast en kies een personage-Blueprint voor elke NPC-spreker (sleep er een in of gebruik de picker), en markeer daarna welke regel de Player is. De health-checkkolom laat zien wat elk personage mist; Fix now levert de componenten meteen aan (de Build-fase zou dat ook automatisch doen).

Voor een Blueprint die net uit de MetaHuman-assembly komt is er een optionele sectie Fresh MetaHuman auto-setup: kies eenmalig je basispersonageklasse en de locomotion Animation Blueprint, waarna de knop Auto-setup per spreker de Blueprint reparent, de Anim Blueprint aan de Body-mesh toewijst, de mesh op de capsule uitlijnt en de dialoogcomponenten aanlevert. Het hele handmatige ritueel, in één klik.

Bouwen en spelen
Open het tabblad Build en druk op RUN. De pipeline compileert de quest:
parse → validate → voice-over → facial animation → asset generation → bind & stage
Een live fasetracker toont de voortgang; fouten verschijnen in de pre-flight checklist boven de knop RUN, elk met een snelkoppeling Fix → die naar het juiste tabblad springt.

Druk op Play (PIE) en praat met de NPC.

Alle gegenereerde content wordt in je project geschreven onder /Game/Questwright/Generated/. De
eigen contentmap van de plugin blijft schoon, en de meegeleverde demoquest kun je verwijderen
zonder iets te breken.
Hoe nu verder
- De Quest Studio: een rondleiding langs elk tabblad.
- Quests schrijven: het
.quest.yaml-formaat. - Instellingenreferentie: elke projectinstelling uitgelegd.
- Liever offline lezen? De volledige documentatie is te downloaden als één printbare pagina of als Markdown-bundel.
De Quest Studio
Eén dockbaar venster (Tools → Quest Studio) stuurt de hele pipeline aan. Deze pagina leidt je langs elke zone; de gelinkte gidsen gaan dieper in op de workflows erachter.

Bibliotheek
De linkerkolom toont elke *.quest.yaml die in je project gevonden wordt (standaard in
Content/Quests/; bestanden verschijnen automatisch, zonder importstap). Bij elke quest staat
een statusbadge:
| Badge | Betekenis |
|---|---|
| Generated & valid | De assets zijn actueel ten opzichte van het bestand |
| Changed | Het bestand is gewijzigd sinds de laatste build; draai gewoon opnieuw RUN |
| Validation errors | Het bestand bevat fouten; open de quest om de bevindingen te zien, met een sprong naar de bron |
| Not built | Nog nooit gecompileerd |
+ New Quest maakt een bestand vanuit een sjabloon. New Chain bundelt quests tot een
verhaalketen: sleep quests in de ketenmap om ze te ordenen. Ketens zijn pure data: slepen
schrijft available_when / priority in de YAML zelf; er is geen verborgen manifest dat corrupt
kan raken.

Quest-tabblad: de constructor
De volledige quest is ter plekke bewerkbaar: scènes, regels, keuzes, emoties, shots, de bedrading tussen stappen, effecten, voorwaarden, beloningen en barks, met de keten- en voorwaardeninformatie op de questkaart. Alles wat de constructor wegschrijft is gewone YAML, dus het bestand met de hand bewerken in een teksteditor is altijd gelijkwaardig, en beide blijven synchroon.

Staging-canvas
In de rechterzone zit een canvas met bovenaanzicht om de deelnemers van een scène neer te zetten: sleep marks om personages te positioneren, draai ze, voeg gespawnde figuranten toe (staat er al of loopt binnen), voeg waypoints toe voor verplaatsingen tijdens de dialoog en plaats eigen camera’s met een live frustumvoorbeeld. Zet de cursor in een dialoogregel en het canvas markeert wie er op dat moment waar staat. Details in Staging en camera’s.

Cast-tabblad
Koppelt elke speaker key aan een personage-Blueprint en markeert de Player. De bind-fase voegt de Questwright-componenten idempotent aan je Blueprints toe; Remove Questwright components zet een personage terug in zijn schone staat. De sectie Fresh MetaHuman auto-setup maakt van een Blueprint die net uit de MetaHuman-assembly komt in één klik een dialoogklaar personage (zie Aan de slag).

Voice-tabblad
Kies per project een TTS-provider, wijs per spreker en per taal een stem toe, beluister losse regels of synthetiseer in batch, of gebruik je eigen WAV-bestanden. Details in Voice-over.

Localization-tabblad
Voeg talen toe, bekijk de vertaaldekking per quest en laat ontbrekende regels machinaal vertalen met je eigen Claude- of OpenAI-sleutel (resultaten worden gemarkeerd als “machinaal, moet nagekeken worden”). Details in Lokalisatie.

Build-tabblad
De pre-flight checklist (bij elke fout een snelkoppeling Fix → naar het juiste tabblad), de taalselectievakjes, de knop RUN, een live fasetracker, Play (PIE) en Show Assets.

Builds zijn idempotent: al ingesproken regels worden overgeslagen, gewijzigde regels worden opnieuw gesynthetiseerd en opnieuw gebakken, en assets van verwijderde regels of stappen worden automatisch opgeruimd.
Quests schrijven
Een quest is één .quest.yaml-bestand. Dat bestand is de bron van waarheid: de Studio
compileert het tot assets en het Quest-tabblad is er een weergave van, dus met de hand bewerken
en in de constructor bewerken zijn altijd gelijkwaardig. Deze pagina loopt door het formaat heen;
de volledige referentie per veld (bewust zo geschreven dat hij ook als AI-prompt dienstdoet) is
beschikbaar als download.
Waar de bestanden staan
Zet quests in <Project>/Content/Quests/; ze verschijnen automatisch in de bibliotheek van de
Studio. Noem ze <Name>.quest.yaml, één quest per bestand.
Minimaal skelet
quest: Region.MyQuest # unique id/slug (required)
name: "My Quest"
giver: Bran # speaker key of the NPC who gives it
source_culture: en
steps: # required, at least 1
- id: MyQuest_Offer
scene:
speakers: [Bran, Player]
lines:
- { by: Bran, id: greet, text: "Hello.", emotion: neutral }
- { by: Player, id: hi, text: "Hi." }
choices:
- { id: accept, text: "I'll help.", goto: MyQuest_Do }
on_end: { quest: accept }
- id: MyQuest_Do
end: completed
De gouden regels
- Stabiele id’s in kleine letters op elke regel, keuze en elk doel. De lokalisatie en de gegenereerde stem- en gezichtsassets zijn op die id’s gesleuteld; content invoegen mag bestaande id’s nooit hernummeren.
- Gebruik alleen gedocumenteerde velden, emoties, shots, voorwaardesoorten en effectwerkwoorden. De validator vangt alles op wat buiten het contract valt, met bij elke bevinding een sprong naar de bron.
- Elke GameplayTag-waarde moet geregistreerd zijn in je project (native in C++ of in
DefaultGameplayTags.ini). Een niet-geregistreerde tag faalt stilzwijgend, en dat is oorzaak nummer 1 van “mijn doel telt nooit mee”. Zie Doelen en voortgang.
Stappen
Een stap is één knoop van de quest: een dialoogscène, een bij te houden doel of een eindmarkering.
| Veld | Functie |
|---|---|
id | Verplicht, stabiel. Krijgt automatisch de namespace <ShortQuest>_<id>. |
scene | Een dialoogscène (regels + keuzes) |
objective | Een bij te houden doel: kill / collect / reach / talk / deliver |
next | Standaardovergang naar de volgende stap (wanneer de scène geen keuzes heeft) |
end | Eindmarkering: completed, declined of failed |
require | Toegangsvoorwaarde, bijvoorbeeld om de inleverstap pas vrij te geven als het doel af is |
Scènes: regels en keuzes
scene:
speakers: [Bran, Mira, Player] # every speaker key present in this scene
lines:
- { by: Bran, id: greet, text: "Come here.", emotion: worried, shot: cu }
- { by: Mira, id: warn, text: "Don't trust him.", to: Player }
- { by: Player, id: what, text: "What's wrong?" }
choices:
- { id: help, text: "I'll help.", goto: MyQuest_Accept }
- { id: refuse, text: "Not my problem.", goto: MyQuest_Refuse }
on_end: { quest: accept }
Een scène ondersteunt een willekeurig aantal sprekers: zet elke key in speakers en stel bij
elke regel by in. Tijdens runtime bindt elke key aan een actor die al in het level staat; is die
er niet, dan wordt er een gespawnd volgens de speaker map die de Cast-fase heeft weggeschreven, en
naast de questgever neergezet. Gespawnde personages worden automatisch verwijderd zodra de
dialoog eindigt.
Handige velden op een regel:
to:benoemt tot wie de regel gericht is; stuurt de over-the-shoulder framing en de hoofddraai aan in scènes met 3 of meer sprekers.emotion:is een vanneutral,happy,sad,angry,afraid,surprised(plus aliassen zoalsworried→afraid). Stuurt de additieve gezichtsstemming en de toon van de voice-over aan.shot:neemtauto(standaard; de compiler kadreert de scène),wide,ots,cu,reaction, of de id van een eigen cameramark (zie Staging en camera’s).echo_of:markeert een regel die de tekst van een keuze herhaalt; geef de id van die keuze op, zodat ze één lokalisatiesleutel delen.
Keuzes kunnen GameplayTags afdwingen en uitdelen: require: maakt een keuze alleen beschikbaar
als de speler de tag(s) bezit, grant: kent tags toe zodra de keuze gemaakt wordt.
Dynamische tekst
Tekst ondersteunt de placeholders {PlayerName} en eigen {Token}-placeholders, die op het
moment van tonen op een lokalisatieveilige manier worden ingevuld. Zie
Runtime-integratie voor het instellen van
tokenwaarden vanuit je game.
Schrijven met een AI-assistent
De snelste weg is de kant-en-klare GPT
Questwright Quest Builder:
die kent het formaat al, dus je hoeft alleen je premisse te beschrijven (“een vuurtorenwachter
vraagt de speler zijn vermiste broer te zoeken”) en je krijgt een complete .quest.yaml terug.
Liever een andere assistent? De volledige formaatreferentie is bewust zelfstandig leesbaar: plak
het referentiebestand samen met je premisse in
ChatGPT of Claude en vraag om een .quest.yaml.
Hoe dan ook: zet het resultaat in Content/Quests/; de validator vangt alles wat buiten het
contract valt op, nog voordat het ooit een build bereikt.
Doelen en voortgang
Alles tussen “accepteren” en “inleveren” staat hier beschreven: hoe doelen worden bijgeschreven, hoe voorwaarden content afschermen, hoe effecten de state veranderen en hoe quests aan elkaar geketend worden.
Doelen
Een bij te houden doel leeft binnen een stap. De stap gebruikt een generieke id (Goal,
Deliver), terwijl de concrete soort in objective.type staat, zodat je die soort kunt wijzigen
zonder iets opnieuw te sleutelen:
- id: Goal
objective:
type: Kill
target: MyGame.Enemy.Wolf # GameplayTag, MUST be registered
count: 3
location: MyGame.Area.Farm # optional area gate
desc: "Kill the wolves near the farm"
next: Deliver
| Type | Betekenis | Hoe het meetelt |
|---|---|---|
Kill | dood N getagde vijanden | jouw doodscode meldt een Kill-event |
Collect | verzamel N getagde items | jouw pickup-code meldt een Collect-event |
Reach | bereik een getagde plek | een Reach-event, of CompleteObjective vanuit een trigger |
TalkTo | praat met iemand | automatisch: een gesprek beginnen telt mee |
Deliver | terugrapporteren aan de questgever | wordt vervuld door het inleveren zelf |
Custom | al het andere | jouw game meldt Custom + je eigen tag |
Twee handige eigenschappen:
TalkToricht zich op een speaker key, niet op een tag (target: Mary, dezelfde key als inspeakers:en op het Cast-tabblad). Elk gesprek met die NPC telt het doel alleen mee voor de pratende speler, en alleen zolang het doel actief is; met de NPC praten voordat je de quest accepteert telt dus terecht niets mee.Deliverblokkeert het inleveren nooit. Het bestaat zodat de tracker een regel “ga terugrapporteren” toont, en wordt automatisch afgevinkt zodra de quest ingeleverd wordt.
Meetellen vanuit je game is één aanroep (Blueprint of C++), server-authoritative en idempotent per
EventSourceId:
Comp->ReportObjectiveEvent(Instigator, EQuestwrightObjectiveEventType::Kill,
MatchTags, LocationTags, EventSourceId);
Tags worden hiërarchisch vergeleken: een doel met target: Enemy.Wolf telt ook mee bij een
event met de tag Enemy.Wolf.Alpha, dus je hoeft niet elk subtype op te sommen.

GameplayTags: de ene cruciale regel
Elke waarde van target, location, require/grant bij een keuze, tag in een voorwaarde en
grant_tag in een effect is een GameplayTag die al geregistreerd moet zijn in je project;
anders lost hij op tot een ongeldige tag en wordt hij stilzwijgend genegeerd. Dit is oorzaak
nummer 1 van “mijn doel telt nooit mee”. Registreren kan op twee manieren:
- Native in C++ (voorkeur voor tags die meegaan naar release):
UE_DEFINE_GAMEPLAY_TAG_COMMENT(...). - Project Settings → Project → GameplayTags (schrijft naar
Config/DefaultGameplayTags.ini).
Gebruik een hiërarchie met punten (MyGame.Enemy.Wolf, MyGame.Area.Farm), dan werkt
hiërarchisch matchen vanzelf. De enige uitzondering: een TalkTo-target is een speaker key, geen
tag.
Voorwaarden
Voorwaarden schermen de beschikbaarheid van een quest af (available_when) en de toegang tot een
stap (require). Atomaire soorten:
| Vorm | Betekenis |
|---|---|
{ quest: <QuestId>, state: <state> } | een andere quest verkeert in een state (available, active, completed, failed, declined) |
{ objective: <ObjId>, state: <state> } | een doel is active / complete / failed / inactive |
{ flag: <Name>, equals: <Value> } | een questvariabele van deze playthrough is gelijk aan een waarde |
{ tag: <GameplayTag> } | de speler bezit een gameplay tag |
{ item: <ItemId>, min: <N> } | de inventory bevat ≥ N van een item (via jouw inventory-provider) |
{ attribute: <AttrId>, min: <N> } | een stat is ≥ N (via jouw stat-provider) |
Samengesteld: { all: [...] } (EN), { any: [...] } (OF), { not: <cond> }.
available_when:
all:
- { quest: Region.Intro, state: completed }
- { not: { flag: Betrayed, equals: "true" } }
Effecten (on_end:)
Worden toegepast zodra een scène wordt verlaten:
on_end:
quest: accept # accept | complete | decline | fail | turnin
set: { RewardTier: Negotiated } # write flags, read back by flag conditions
grant_tag: Region.MetBran # grant gameplay tag(s) to the player
grant_quest: Region.FollowUp # auto-accept follow-up quest(s)
Een inleverscène eindigt doorgaans met on_end: { quest: turnin } plus end: completed.
Vertakken op keuzes van de speler
Wil je dat de questgever reageert op een eerdere keuze, zet dan een flag op het moment van die
keuze en schrijf vervolgens twee inleverstappen: die met de flag-voorwaarde eerst, de
vangnetstap als laatste. De routering van de questgever kiest de eerste inleverstap waarvan
require slaagt:
- id: Haggle
scene: { ... }
on_end: { quest: accept, set: { RewardTier: Negotiated } }
- id: DeliverHaggled # specific branch; keep it before the catch-all
require:
all:
- { objective: Goal, state: complete }
- { flag: RewardTier, equals: Negotiated }
scene: { ... }
on_end: { quest: turnin }
end: completed
- id: Deliver # default branch, carries the tracked objective
require: { objective: Goal, state: complete }
objective: { type: Deliver, count: 1, desc: "Report back" }
scene: { ... }
on_end: { quest: turnin }
end: completed
De meegeleverde demoquest gebruikt precies dit patroon (afdingen leidt tot een andere uitbetalingsscène).
Questketens
Een keten is niet meer dan data; er is geen apart asset:
available_when: { quest: A, state: completed }bij quest B (voorwaarde vooraf), en/ofon_end: { grant_quest: B }bij quest A (het vervolg automatisch accepteren).
priority bepaalt de volgorde van meerdere quests die één questgever aanbiedt (hoger eerst). De
New Chain-UI van de Studio schrijft deze waarden voor je weg met drag & drop; met de hand
schrijven is gelijkwaardig. De validatie vangt cycli in ketens en losse verwijzingen naar quests
of doelen op.
Barks
Sfeerbarks (barks:) klinken boven het hoofd van de questgever op een willekeurige timer; idle
barks (idle_barks:) klinken bij interactie wanneer de questgever niets meer te bieden heeft.
Beide gaan door dezelfde voice-over- en gezichtspipeline, in de stem van de questgever:
barks:
interval: [8, 16]
lines:
- "Wolves howling again..."
- { text: "After dark, nobody sets foot in the yard.", weight: 2 }
idle_barks:
lines:
- "Rest easy. The farm's safe, thanks to you."
Beloningen
rewards:
base:
currency: 20
xp: 50
items:
- { def: SmokedMeat, count: 1 }
currency, xp en items worden bij het inleveren vastgelegd; jouw game deelt de daadwerkelijke
goederen uit via het koppelvlak van de inventory-provider (zie
Runtime-integratie).
Staging en camera's
Zonder enige staging zet Questwright simpelweg elke spreker met het gezicht naar zijn gesprekspartner en kadreert het de scène automatisch; veel quests hebben nooit meer nodig. Staging is er voor blocking met meerdere NPC’s, gespawnde figuranten, verplaatsingen tijdens de dialoog en handmatig geplaatste camera’s.
Het staging-canvas
De rechterzone van de Studio is een canvas met bovenaanzicht van de scène rond haar anker (een geplaatste dialoogmarker, of de transform van de questgever zelf als je er geen plaatst). Sleep marks om personages te positioneren, draai ze, voeg waypoints toe en plaats camera’s. Zet de cursor in een dialoogregel en het canvas markeert wie er op dat moment waar staat: de bezetting wordt regel voor regel door de hele scène heen bijgehouden.

Alles wat je op het canvas bewerkt, wordt weggeschreven naar het staging:-blok van het
questbestand. Net als bij de rest van de Studio is met de hand schrijven gelijkwaardig:
staging:
anchor: DialogueMarker_Barn # a placed BP_QW_DialogueMarker; omit → the giver's transform
settle_timeout: 4.0 # seconds a walk may take before falling back to teleport
marks:
- { id: giver, actor: Bran, pos: [-100, -30], face: hero, keep: true }
- { id: hero, actor: Player, pos: [-100, 60], face: giver }
- { id: m1, actor: Mira, pos: [ 140, 30], face: anchor, appear: arrive }
- { id: m2, actor: Mira, pos: [ 40, -80], face: anchor } # waypoint
De belangrijkste velden van een mark:
| Veld | Functie |
|---|---|
id | Stabiele id; line.stage.to en camera’s verwijzen met de id naar marks |
actor | Speaker key; laat weg voor een puur waypoint |
pos | [x, y] in cm, ten opzichte van het anker; de hoogte wordt tijdens runtime op de grond vastgezet |
face / yaw | Automatisch draaien naar het anker / een spreker / een mark, of een handmatige hoek |
appear | placed (staat er al bij het begin van de scène) of arrive (spawnt buiten beeld en loopt binnen; zijn eerste regel wacht op aankomst) |
keep | Of een gespawnde deelnemer blijft staan nadat de dialoog eindigt (standaard: despawnen) |
Deelnemers die al in het level staan (en de Player) worden verplaatst; alle anderen worden gespawnd vanuit de cast en automatisch opgeruimd.
Verplaatsen tijdens de dialoog
Hang een stage:-overgang aan een willekeurige regel; de regel wacht tot de verplaatsing klaar is
(met een teleport als terugval na settle_timeout):
- { by: Mira, id: step, text: "Let me see the tracks.",
stage: [ { who: Mira, to: m2, approach: walk } ] }
Eén mark houdt één deelnemer tegelijk vast: de validator markeert twee mensen op dezelfde mark op hetzelfde moment als een fout, en het canvas toont het conflict.
Automatische camera’s
Standaard kadreert de compiler elke scène met een shotgrammatica: een establishing wide op de
eerste regel, close-ups na meerdere opeenvolgende regels van dezelfde spreker en
over-the-shoulder framing op basis van de geadresseerde in to: van elke regel. Per regel
overschrijf je dat met shot: (wide, ots, cu, reaction), en het beleid per quest is
instelbaar:
camera:
cu_run_threshold: 2 # close-up after N consecutive lines from one speaker (default 3)
establishing: true # establishing wide on the first line (default true)
choice_shot: wide # shot while the player is choosing (default wide)
Eigen cameramarks
Voor volledige regie zet je camera’s op het canvas; elke camera krijgt een live frustumvoorbeeld, zodat je precies ziet wat hij kadreert:

staging:
cameras:
- { id: cam_quick, class: dynamic, pos: [200, 0], height: 200, look_at: anchor }
- { id: cam_window, class: BP_MyCam_Voyeur, pos: [-320, 90], height: 150, look_at: giver, fov: 28 }
- { id: cam_dutch, class: BP_MyCam_Dutch, pos: [140, 200], height: 120, yaw: -135, pitch: -8 }
# on a line: shot: cam_window
# while choices unfold: camera: { choice_shot: cam_high }
Hoe het in elkaar past:
- De mark is een instantie: een stabiele id, een positie ten opzichte van het anker en een
richting. Regels verwijzen via
shot:naar de id van de mark, nooit naar een klasse of naar coördinaten. - De herbruikbare optiek (lens / DOF / filmback) zit in een cameraklasse, oftewel in elke
Blueprint-subklasse van
QuestwrightDialogueSceneCamera. Het ingebouwdeclass: dynamicheeft helemaal geen Blueprint nodig (standaardoptiek; combineer metfov:voor een snelle eigen hoek). look_atricht op het anker, een spreker of een mark en wordt op het moment van de cut opgelost, zodat een camera zijn onderwerp in beeld houdt, ook na verplaatsingen tijdens de dialoog.- De automatische grammatica kiest nooit eigen marks; die gelden alleen als expliciete
overschrijving per regel (of via
choice_shot). - Laadt een cameraklasse tijdens runtime niet, dan valt de regel terug op een wide shot met een waarschuwing; de scène breekt nooit.
Ontwerpnotities
Camera’s snijden direct (SetViewTargetWithBlend met blend nul) en personages bewegen met de
eigen AI-locomotie van de engine. Er is geen Sequencer en er zijn geen gebakken cinematics, en
daarom blijven scènes werken wanneer je level, personages of animaties veranderen. Alle
verwijzingen gaan naar stabiele id’s (marks, regels, quests), nooit naar coördinaten of naar de
binnenkant van klassen.
Voice-over
Elke dialoogregel, bark en idle bark kan voice-over dragen. De buildfase resolve-audio synthetiseert (of importeert) één audio-asset per regel en per taal, waarna de gezichtsfase daaruit de lipsync bakt (zie Gezichtsanimatie).
Providers
Drie uitwisselbare providers, te kiezen op de tabbladen Voice/Build:
| Provider | Wat het is | Kosten |
|---|---|---|
| Provided | Je zet WAV-bestanden met de namen van de regel-id’s in VO_Source/<culture>/ | — |
| OmniVoice | Een lokale HTTP-TTS-server; met één klik op Setup & Launch vanaf het tabblad Voice | gratis, lokaal |
| ElevenLabs | Cloud-TTS met je eigen API-sleutel | je eigen account |
Er wordt niets meegeleverd en er belt niets naar huis: OmniVoice draait op je eigen machine, ElevenLabs gebruikt jouw sleutel, en met eigen WAV’s (Provided) werkt de plugin volledig offline.
Stemmen toewijzen
Stemmen wijs je per spreker en per taal toe op het tabblad Voice: hetzelfde personage kan een Engelse stem hebben en een Russische stem met een andere casting. Je kunt één regel beluisteren, één regel opnieuw genereren of alles wat ontbreekt in één keer synthetiseren.

Synthese is idempotent: bij een rebuild worden al ingesproken regels overgeslagen, gewijzigde
regels opnieuw gesynthetiseerd en audio van verwijderde regels opgeruimd. Gegenereerde
geluidsassets krijgen de naam van de stabiele regel-id’s (<Step>_<line>_<Speaker>), en juist
daarom mogen id’s nooit hernummerd worden.
OmniVoice opzetten
OmniVoice is een lokale TTS-server met open source: github.com/debpalash/OmniVoice-Studio. Kloon of download die repository ergens op je machine — de Studio doet de rest.
Wijs met Repo path naar de gedownloade repository en druk op Setup & Launch (alleen
nodig als je de server niet zelf al hebt gestart — draait er al een server, laat de URL er dan
gewoon naar wijzen). De knop installeert de afhankelijkheden en start de server, en vangt
daarbij de valkuilen van de console-omgeving af die een handmatige start laten mislukken; de
eerste keer worden ook de ML-modellen gedownload, wat enkele minuten kan duren zonder enige
uitvoer. Wacht tot de statusregel groen wordt. Start de server niet, kijk dan in
_qw_omnivoice.log naast de serverbestanden.

Zodra de server draait, druk je op Fetch voices om elke spreker die de server op dat moment aanbiedt in de stemkeuzelijsten per spreker te laden.

Meer variatie nodig? Open de keuzelijst Add preset met de samengestelde stempresets van de server en kies degene die je wilt — na de klik verschijnt die vanzelf als optie in de stemkeuzelijsten van je sprekers.

Waar de configuratie staat
De provider/het model per cultuur en de stemtoewijzing per spreker zijn projectinstellingen: het
tabblad Voice bewerkt Project Settings → Plugins → Questwright Studio (BuildCultures,
VoiceByCulture), bewaard in DefaultGame.ini zodat het hele team ze deelt. Zie de
Instellingenreferentie.
API-sleutels worden nooit in projectbestanden bewaard. Sleutels staan in een ini per
gebruiker (buiten git gehouden) met een omgevingsvariabele als fallback
(QW_ELEVENLABS_KEY), wat veilig is voor teams en CI.
Je eigen opnames
Wil je opgenomen VO gebruiken, kies dan de provider Provided en zet WAV’s met de namen van
de regel-id’s in VO_Source/<culture>/. Mengen mag: synthetiseer tijdens de productie
tijdelijke opnames met OmniVoice en vervang ze later door studio-opnames; de id’s veranderen
niet, dus de rest ook niet.
Gezichtsanimatie
Questwright heeft geen performance capture nodig: gezichtsanimatie wordt gebakken uit de audio van de voice-over. Heeft een regel VO, dan krijgt ze lipsync, of de audio nu uit TTS komt of uit je eigen opnames.
Het bakken (tijdens de build)
De gezichtsfase van de build draait MetaHuman Animator op elke ingesproken regel en bakt per
regel een UAnimSequence met lipsync (FA_<LineId>), waarbij de stemming volgt uit de waarde
van emotion: bij die regel. Net als elke fase is ze idempotent: ongewijzigde regels worden
overgeslagen en verweesde gezichtsanimaties van verwijderde regels worden opgeruimd.
Vereisten voor deze fase: de MetaHuman plugin ingeschakeld en DX12. Beide worden gecontroleerd in de pre-flight op het tabblad Build; met een schakelaar voor gezichten kun je de fase daar helemaal overslaan (builds voor snelle iteratie).
Lagen tijdens runtime
Tijdens runtime stapelt de plugin het gezicht in code op elke MetaHuman; de Animation Blueprints van je personage worden nooit aangepast:
lip-sync slot → procedural blinking → additive emotion → eye gaze → the character's own RigLogic
De hoofddraai naar de huidige spreker wordt toegepast via een post-process Anim Blueprint op het lichaam tijdens runtime (bij MetaHumans wordt de hoofdbotpose vanaf het lichaam geleid), zodat personages vanzelf kijken naar wie er praat, ook na verplaatsingen in de staging midden in een dialoog.

Altijd een zachte landing
Elk onderdeel van de gezichtspipeline degradeert netjes in plaats van de build of de scène te breken:
| Situatie | Resultaat |
|---|---|
| Geen MetaHuman plugin / geen DX12 | Gezichtsfase overgeslagen met een waarschuwing; de dialoog speelt met een neutraal gezicht |
| Personage is geen MetaHuman | Dialoog, staging en camera’s werken; geen gebakken lipsync |
| Een gezichtsasset laadt niet | Neutraal gezicht voor die regel, waarschuwing in de log |
De Anim Blueprint-klassen voor gezicht en hoofdbeweging zijn soft references die tijdens runtime pas op het laatste moment worden opgelost, dus de plugin laadt prima in projecten zonder ook maar enige MetaHuman-content.
Gelokaliseerde gezichten
Elke taal krijgt zijn eigen voice-over en zijn eigen lipsyncbake: een Russische regel beweegt de mond als het Russisch. Assets per cultuur worden in packaged builds omgewisseld door het lokalisatiesysteem van de engine (zie Lokalisatie voor de kanttekening over PIE).
Lokalisatie
Lokalisatie zit in de pipeline ingebouwd en is er niet aan vastgeschroefd: elke taal krijgt zijn eigen tekst, voice-over en lipsyncanimatie, geproduceerd door dezelfde build.
Hoe het is georganiseerd
- Schrijf quests in één brontaal (de
source_culturevan de quest, bijvoorbeelden). - Vertalingen zijn CSV-sidecars (
Loc/<Quest>.<culture>.csv) met de stabiele regel-id’s als sleutel. Onvertaalde sleutels vallen terug op de brontekst; het bronbestand wordt nooit overschreven. - De culturen die je project bouwt, staan in Project Settings → Plugins → Questwright Studio → Build Cultures (het tabblad Localization beheert dat voor je).
Het tabblad Localization
Voeg talen toe, bekijk de dekking van de vertaling per quest en laat ontbrekende regels machinaal vertalen met je eigen sleutel van Claude of OpenAI. Machinale resultaten worden gemarkeerd als “machine, needs review”, zodat een menselijke ronde makkelijk te volgen is. Sleutels worden per gebruiker bewaard (nooit in de repo), net als de sleutels voor voice.

Talen bouwen
Het tabblad Build heeft een checkbox per cultuur. Elke gebouwde taal krijgt:
- eigen String Tables (dialoog, keuzes, journaaltekst);
- een eigen voice-over, met de stemmencast per taal van het tabblad Voice;
- een eigen lipsyncbake uit de audio van die taal.
Assets per cultuur staan onder /L10N/<culture>/ en worden omgewisseld door het eigen
lokalisatiesysteem van de engine.
De ene kanttekening: PIE versus packaged
Unreal past het omwisselen van assets per cultuur (audio, gezichtsanimatie) alleen toe in packaged/cooked builds; in PIE hoor je altijd de stem van de broncultuur. Tekstlokalisatie werkt overal, ook in PIE. Dit is gedrag van de engine, geen instelling die je kunt rechtzetten; test gelokaliseerde VO in een packaged build.
Dynamische tekst en lokalisatie
De placeholders {PlayerName} en eigen {Token}-placeholders overleven de vertaling. Het
vervangen gebeurt op het moment van tonen via FText::Format, zodat vertalers de tokens binnen
een zin vrij kunnen herschikken.
Runtime-integratie
Questwright is engine-native en staat op zichzelf; het integratieoppervlak is bewust klein. Deze pagina beschrijft elk raakvlak tussen de plugin en de code van je game (C++ of Blueprint).
Het questcomponent
Questvoortgang is een feit over de combinatie (speler, quest). Ze leeft op
UQuestwrightQuestComponent, dat automatisch aan elke PlayerState wordt toegevoegd (en nooit
op NPC’s wordt bewaard). Je haalt het overal op:
UQuestwrightQuestComponent* Comp = UQuestwrightQuestComponent::Get(SomeActor);
UQuestwrightQuestComponent* Local = UQuestwrightQuestComponent::GetLocalPlayer(World);
Doelen bijschrijven
Gebeurt er iets wat relevant is voor een quest, zoals een kill of het oppakken van een item,
doe dan één aanroep (BlueprintCallable, server-authoritative, idempotent per EventSourceId):
Comp->ReportObjectiveEvent(Instigator, Type, MatchTags, LocationTags, EventSourceId);
Elk actief doel waarvan type en de (hiërarchisch gematchte) tags target/location bij het
event passen, telt op. Geef je de killer mee als Instigator, dan wordt alleen die speler
bijgeschreven; geef je niemand mee, dan gaat het naar alle spelers (fallback voor een gedeelde
wereld). Voor verhaalmomenten kan een trigger of dialoog in plaats daarvan aanroepen:
Comp->CompleteObjective(QuestId, ObjectiveId);
UI uit de doos
Voeg UQuestwrightQuestHUDComponent toe aan je PlayerController en je krijgt de doeltracker op
het scherm, het questjournaal (koppel een toets aan ToggleJournal) en toasts met de
queststatus.

Alle widgets zijn in C++ gebouwd en vervangbaar door je eigen subclasses. Of sla ze volledig over en stuur een eigen UI aan met de delegates hieronder.
Koppelpunten voor providers
In plaats van een eigen inventory of stats mee te leveren, praat Questwright met die van jou via interfaces met werkende standaardimplementaties:
| Koppelpunt | Interface | Te implementeren in |
|---|---|---|
| Inventory (voorwaarden op items, itembeloningen) | IQuestwrightInventoryProvider | Blueprint of C++ |
| Stats / attributen (voorwaarden op attributen) | IQuestwrightStatProvider | Blueprint of C++ |
| Backend voor opslaan | IQuestwrightSaveProvider | C++ |
| Spraaksynthese | IQuestwrightVoiceProvider | C++ (editor) |
| Ontvanger voor gezichtsanimatie, smart objects | provider-interfaces | C++ |
Queststatus als GameplayTags
Roep SetTagTargetActor(Pawn) aan en het component projecteert de tags
Questwright.Quest.State.* op een AbilitySystemComponent: de queststatus wordt daarmee
bruikbaar in de activatievoorwaarden van abilities en in elk voorwaardensysteem op tags dat je
al hebt.
Delegates
Voor een eigen UI of reacties in de game:
OnQuestStateChanged: geaccepteerd / voltooid / geweigerd / mislukt;OnObjectivesChanged: een teller is verschoven of een doel is voltooid;OnJournalDirty: er is iets veranderd aan wat het journaal toont;OnProgressLoaded: bewaarde voortgang is toegepast (zie Opslaan & multiplayer).
Tokens voor dynamische tekst
De placeholders {PlayerName} en eigen {Token}-placeholders in dialoog- en journaaltekst
worden op het moment van tonen vervangen door een subsysteem van de GameInstance:
UQuestwrightTextVarsSubsystem* Vars = GameInstance->GetSubsystem<UQuestwrightTextVarsSubsystem>();
Vars->SetPlayerName(TEXT("Ellie"));
Vars->SetTextVar(TEXT("Faction"), TEXT("Rangers")); // used as {Faction}
Beide setters zijn BlueprintCallable. De vervanging gebruikt FText::Format en is dus veilig
voor lokalisatie.
Brug dialoog → quest
Dialoogscènes veranderen de queststatus via hun on_end-effecten (quest: accept / turnin / decline / fail, set:-vlaggen, grant_tag, grant_quest), zodat je geen lijmcode tussen
gesprekken en quests hoeft te schrijven. Zie
Doelen & progressie.
Opslaan & multiplayer
Questvoortgang blijft uit de doos bewaard: in single player schrijf je geen regel code, en hetzelfde model schaalt met één interface door naar dedicated servers.
Autosave / autoload
Het questcomponent van elke speler laadt bij de start de bewaarde voortgang en slaat op na wijzigingen (accepteren, doel bijschrijven, naar een volgende stap gaan, vlaggen, voltooien). Opslagacties worden samengevoegd: een reeks wijzigingen binnen één frame kost één schrijfactie. Bij afsluiten, map travel en uitloggen volgt een laatste opslag, en autoload herstelt de voortgang automatisch bij het wisselen van level.
Het beleid stel je in via Project Settings → Plugins → Questwright Quests (details in de Instellingenreferentie):

Automatisch bewaren treedt in werking voor componenten die eigendom zijn van een
PlayerState (de standaard uitrol); componenten op kale actors blijven volledig handmatig
met SaveProgress() / LoadProgress().
Wat er wordt bewaard
Alleen de voortgangsrecords per speler: status, huidige stap, doeltellers, vlaggen, tijdstempels. De inhoud van een quest leeft in de gecompileerde assets; een actieve dialoogscène is presentatie en wordt nooit bewaard. Bewaarde voortgang overleeft contentupdates: een record waarvan de opgeslagen stap niet meer bestaat, valt terug op de eerste stap van de quest (met een waarschuwing in de log), en records van quests die de huidige build niet kent, blijven ongemoeid.
De drie niveaus
| Uitrol | Wat je doet |
|---|---|
| Single player | Niets. Eén USaveGame-slot (Questwright_Quests). |
| Co-op op een listen server | Niets. Elke speler krijgt een eigen slot met zijn online-id als sleutel (Questwright_Quests_<id>). |
| Dedicated server / eigen backend | Implementeer één C++-interface (hieronder). |
Het koppelpunt voor de backend is IQuestwrightSaveProvider:
class UMyDbSaveProvider : public UObject, public IQuestwrightSaveProvider
{
// PlayerKey is the player's UniqueNetId string; use it as your database key.
virtual bool SaveQuestRecords(const FString& PlayerKey,
const TArray<FQuestwrightQuestRecord>& Records) override;
virtual bool LoadQuestRecords(const FString& PlayerKey,
TArray<FQuestwrightQuestRecord>& Out) override;
// Optional non-blocking variant for REST/database fetches:
// virtual void LoadQuestRecordsAsync(...) override;
};
Registreer die als SaveProviderClass op de instellingenpagina, of injecteer bij het inloggen
een instantie met SetSaveProvider(). Alles draait aan de serverkant; clients krijgen de
geladen voortgang via de normale replicatie.
Handmatige aansturing
Voor een game met opslagpunten: zet AutoSavePolicy op Manual en roep zelf
SaveProgress() / LoadProgress() aan. OnProgressLoaded vuurt nadat de bewaarde voortgang is
toegepast.
Multiplayermodel
Questwright werkt in standalone, op een listen server en op een dedicated server, met een strikte server-authoritative scheiding:
- Voortgang is per speler, in een component op de PlayerState, gerepliceerd alleen naar de eigenaar, zodat spelers nooit de binnenkant van elkaars journaal zien.
- Alle mutaties zijn server-authoritative. Aanroepen vanaf de client (een quest accepteren vanuit de UI, een event melden) lopen automatisch via Server RPC’s; de API ziet er aan beide kanten hetzelfde uit.
- Kill credit gaat naar de speler die de kill maakte, als je code voor sterfgevallen de killer meegeeft; anders wordt het aan alle spelers bijgeschreven (fallback voor een gedeelde wereld).
- Presentatie draait nooit op de server. Camera’s, gezichten, dialoog-UI en look-at draaien alleen op de client van de eigenaar; een dedicated server voert er niets van uit.
- Componenten worden bij het inloggen automatisch aangemaakt, dus wie later binnenkomt, krijgt de zijne vanzelf.
Instellingenreferentie
Questwright registreert drie pagina’s onder Project Settings → Plugins. Ze werken allemaal
op projectniveau (DefaultGame.ini) en worden via versiebeheer met je team gedeeld, met één
bewuste uitzondering: API-sleutels worden hier nooit bewaard (die staan in een ini per
gebruiker, buiten git gehouden, met een omgevingsvariabele als fallback).
Questwright Quests
Het bewaren van questvoortgang. Configsectie:
[/Script/QuestwrightRuntime.QuestwrightQuestSettings].

| Instelling | Standaard | Wat het doet |
|---|---|---|
Auto Load Progress (bAutoLoadProgress) | Aan | Laadt de bewaarde voortgang wanneer het questcomponent van een speler start (aan de serverkant). Herstelt de voortgang ook bij map travel, waar de PlayerState opnieuw wordt aangemaakt. |
Auto Save Policy (AutoSavePolicy) | On any change | Wanneer voortgang automatisch wordt opgeslagen. Manual betekent nooit (je roept zelf SaveProgress() aan); On quest state change slaat alleen op bij overgangen in de levenscyclus (accepteren / voltooien / weigeren / mislukken); On any change slaat daarnaast op bij stapovergangen, bijgeschreven doelen en vlaggen. Opslagacties worden samengevoegd: een reeks wijzigingen binnen hetzelfde frame kost één schrijfactie. |
Save On End Play (bSaveOnEndPlay) | Aan | Een laatste wegschrijfactie voor de zekerheid wanneer het component End Play bereikt (afsluiten / travel / uitloggen). Zet dit samen met Manual uit voor volledig handmatig bewaren. |
Save Provider Class (SaveProviderClass) | None | Backend voor de opslag (C++-klasse die IQuestwrightSaveProvider implementeert). None = de ingebouwde provider op basis van USaveGame-slots. Zie Opslaan & multiplayer. |
Automatisch bewaren treedt alleen in werking voor questcomponenten die eigendom zijn van een PlayerState (de standaard uitrol). Componenten op kale actors blijven volledig handmatig opslaan en laden.
Questwright Dialogue
Het tempo van dialogen tijdens runtime. Configsectie:
[/Script/QuestwrightRuntime.QuestwrightDialogueSettings].

| Instelling | Standaard | Wat het doet |
|---|---|---|
Advance Mode (AdvanceMode) | Manual | Hoe regels doorlopen. Manual wacht na elke regel op een klik (de lezer bepaalt het tempo). Auto laat regels spelen en na de voice-over vanzelf doorgaan; alleen keuzes wachten op invoer (filmisch tempo). |
Auto Advance Buffer Seconds (AutoAdvanceBufferSeconds) | 0.4 | Auto-modus: extra seconden die na de voice-over van een regel worden aangehouden voordat er wordt doorgegaan, een kleine adempauze tussen regels. |
Auto Advance No Voice Seconds (AutoAdvanceNoVoiceSeconds) | 2.5 | Auto-modus: hoe lang een regel zonder voice-over in beeld blijft, zodat de tekst nog te lezen is. |
Beide waarden voor de Auto-modus zijn alleen bewerkbaar wanneer Advance Mode op Auto staat.
Questwright Studio
De culturen voor lokalisatie en de voice-configuratie per cultuur, normaal gesproken bewerkt via
de tabbladen Localization en Voice in plaats van met de hand. Configsectie:
[/Script/QuestwrightStudio.QuestwrightStudioSettings].

| Instelling | Wat het doet |
|---|---|
Build Cultures (BuildCultures) | De set culturen die het project bouwt (bijvoorbeeld en, ru). De eerste vermelding is de fallback voor de broncultuur wanneer een quest geen eigen source_culture opgeeft. Leeg = schrijven in één cultuur. |
Voice By Culture (VoiceByCulture) | Voice-configuratie per cultuur, met de cultuurcode als sleutel. Elke vermelding bevat de TTS-provider (bijvoorbeeld OmniVoice, ElevenLabs), een model van die provider, een hint voor het outputformaat (bijvoorbeeld wav_24000) en de stemtoewijzing per spreker (sleutel van de spreker → id van de stem bij de provider). |
Wat er niet in Project Settings staat
| Waarde | Waar het staat |
|---|---|
| API-sleutels van ElevenLabs / Claude / OpenAI | Ini per gebruiker (buiten git) + fallback via de omgeving, bijvoorbeeld QW_ELEVENLABS_KEY |
| Questcontent, ketens, prioriteiten | De .quest.yaml-bestanden zelf; er is geen verborgen manifest |
| Gegenereerde assets | De map /Game/Questwright/Generated/ van je project |
Problemen oplossen & FAQ
Problemen oplossen
| Symptoom | Oorzaak / oplossing |
|---|---|
| Een doel telt nooit mee | De GameplayTag bij target/location is niet in het project geregistreerd; zie Doelen & progressie. Dit is probleem nummer één. |
| De dialoog speelt, maar er is geen lipsync | De MetaHuman plugin staat uit, of er is geen DX12, waardoor de gezichtsfase zoals bedoeld terugvalt op een neutraal gezicht. Los de vereiste op en draai Build opnieuw. |
| Een eigen camera schakelt niet in | De shot: van de regel moet verwijzen naar een gedeclareerde id uit staging.cameras. Laadt de cameraklasse niet, dan valt de scène met een waarschuwing terug op een wide shot. |
| OmniVoice start niet | Gebruik de knop Setup & Launch op het tabblad Voice (die vangt de valkuilen van de console/venv-omgeving af); kijk in _qw_omnivoice.log naast de server. |
| RUN is grijs | De pre-flight checklist bevat rode punten; elk punt heeft een snelkoppeling Fix → naar het juiste tabblad. |
| Stemmen/gezichten in de verkeerde taal in PIE | Dat hoort zo: het omwisselen van assets per cultuur werkt alleen in een cooked build, terwijl tekstlokalisatie overal werkt. Zie Lokalisatie. |
| De quest is gewijzigd, maar de assets zijn oud | De Library markeert die als “changed”; draai gewoon opnieuw RUN. Het genereren is idempotent en ruimt verweesde stem- en gezichtsassets van verwijderde regels op. |
| Twee deelnemers belanden op dezelfde plek | Twee marks (of een verplaatsing midden in de dialoog) zetten twee personen op hetzelfde moment op dezelfde mark. Zowel de validator als het staging-canvas markeert de conflicterende regel. |
FAQ
Heb ik MetaHumans nodig?
Nee. Dialoog, quests, staging, camera’s, het journaal en opslaan werken met elk personage met een skeletal mesh. De MetaHuman-pipeline voedt alleen de gebakken lipsync en de gelaagde gezichtsanimatie; zonder die pipeline valt de build netjes terug op een neutraal gezicht.
Moet ik C++ schrijven?
Nee. Opzetten kost één klik, doelen worden bijgeschreven met één BlueprintCallable node, en de
koppelpunten voor inventory/stats zijn in Blueprint te implementeren. C++ is alleen nodig voor
een eigen backend voor opslaan (IQuestwrightSaveProvider).
Werkt het in multiplayer / co-op?
Ja: standalone, listen server en dedicated server. Voortgang is per speler, replicatie gaat alleen naar de eigenaar, alle mutaties zijn server-authoritative en opslaan in co-op werkt zonder code. Zie Opslaan & multiplayer.
Kunnen quests tijdens runtime procedureel worden gegenereerd?
Niet tijdens runtime. Een quest is geschreven content die de Studio (of de compile-commandlet in
CI) tot assets compileert. Wat je wel kunt automatiseren, is het schrijven: .quest.yaml is
platte tekst, dus scripts of een AI-assistent kunnen questbestanden genereren die je daarna
gewoon bouwt.
Kan ik dialoog importeren uit externe tools (articy, Twine, spreadsheets)?
Er is geen ingebouwde importer, maar het doelformaat is een open, gedocumenteerd tekstbestand; de authoring reference beschrijft elk veld. Converteren vanuit elke gestructureerde bron is een klein scriptje, en de referentie samen met je brontekst in een AI-assistent plakken werkt ook prima.
Kan ik de UI restylen of vervangen?
Ja. Alle widgets (dialoog, keuzes, journaal, tracker, toasts, barks) zijn in C++ gebouwd met
klassen die je in Blueprint kunt subclassen, en met de delegates OnQuestStateChanged /
OnObjectivesChanged / OnJournalDirty stuur je in plaats daarvan een volledig eigen UI aan.
Is het afhankelijk van andere betaalde plugins of onlinediensten?
Nee. De plugin is engine-native en staat op zichzelf. Spraaksynthese en machinevertaling zijn optioneel en gebruiken je eigen diensten/sleutels; met je eigen WAV-bestanden draait alles volledig offline.
Welke engineversies worden ondersteund?
Unreal Engine 5.6 – 5.8. De compatibiliteitslaag wordt bij het compileren gecontroleerd, dus een verkeerde versie faalt luid tijdens de build in plaats van stilletjes tijdens runtime.
Mijn game is gestileerd / niet fotorealistisch. Is de filmische camera verplicht?
Shots schrijf je per regel, dus jij bepaalt hoeveel “cinema” een scène krijgt, van volledig eigen cameramarks tot gewone gesprekken, en de UI-widgets mag je naar je genre restylen.
Kom je er nog niet uit?
Schrijf naar support@phoenixtools.dev met je engineversie, zo mogelijk het questbestand, en de relevante regels uit de Output Log.