Changelog
All notable changes to the LocalNPC package will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
Added
- A sample head and a head demo scene.
Samples/Head/LocalNPC Head.prefabis a head with neck, teeth, tongue and eyes (6,126 triangles, the 12 ARKit shape keysjawOpen,mouthClose,mouthFunnel,mouthPucker,mouthSmileLeft/Right,mouthLowerDownLeft/Right,mouthUpperUpLeft/Right,eyeBlinkLeft/Right), and01_QuickStart/QuickStartHead.unityis the QuickStart NPC with this head in place of the capsule. The head opens its jaw with the loudness of the voice; other mouth shapes need the optional uLipSync package, and the head does not blink. The prefab carriesAmplitudeLipSynconjawOpenand a switched-offBlendShapeVisemeMapperwith the ARKit preset for uLipSync.SampleShaded.shaderhas a Base Map texture slot, white by default, so the other samples look as before. - Setup Wizard row "Windows voice installed". The Setup Wizard, step 1 (Environment & Hardware), shows which Windows voice the NPC would use for en-US. When there is none, the row is a yellow warning with the same text the runtime logs; it does not block anything.
- A voice and speaking rate for each NPC.
NpcAgenthas a Voice dropdown (the OneCore voices installed on this PC whose main language is the profile's, for en-US also en-GB and en-CA, the profile's exact tag first; Windows "natural" Narrator voices are not listed, as apps cannot use them) and a Speaking Rate slider (0.6 to 1.5, or the default 0.9), and the propertiesSystemVoiceandSpeakingRate, read when the agent starts. An agent with neither set uses the shared voice as before. A voice missing on the player's PC falls back to the profile's voices, then any voice of the language, then SAPI 5. NpcAgent.GetInstalledVoices(languageTag)lists the Windows voices installed on the PC for a language, each as anNpcVoiceInfowith aName(a value forSystemVoice) and aLanguage, for example for a voice menu of your own. It plays no sound, lists every voice when the tag is empty, and is empty when the voice library is missing.
Changed
- The default voice speed is now 0.95 (was 0.9).
- The Diagnostics window's reply-time target is now 2500 ms (was 1000 ms). It counts after the end-of-speech wait, as before, and is information, not a promise: the turns measured on one laptop (about 2 s) now show within it, and slower PCs may show above it. A turn's status box now says "within" or "above" by the time to the first audio only; the stage budgets are still listed in its breakdown. The chart's target line follows the same value.
- The documents give the reply time. Typically about 3 seconds after you stop talking: a 0.9 second end-of-speech wait plus about 2 seconds (measured 2.04 to 2.25 s on one laptop, Balanced preset, five voice turns, read from the sample scenes' "Time to first audio" in a hand test on 27 and 28 October 2026). It depends on your hardware, and we have not measured other machines yet. The README, the documentation index, Performance Tuning and the known issues in Troubleshooting said it had not been measured. The entries below that say so are kept as history.
Third-Party Notices.txtlists the KaTeX fonts and more copyright lines. The 20 KaTeX fonts inside the web page bundled into the two LlamaLib libraries have their own entry and licence text, the SIL Open Font License 1.1 (text 4.16), with the copyright lines written in the font files. The notices also give the copyright lines of OpenSSL (from its README) and of pdf.js (Copyright 2024 Mozilla Foundation), and say that LlamaLib states none. No library or file in the package changed.- The head demo scene has its own NPC to match the sample head: Corin of Hollowmere, a man, with the same town, tone, reply length and safety lines as Mira, and the Microsoft David voice; a PC without David uses the default voice (Microsoft Mark, or the next installed voice), with no error. The QuickStart scene keeps Mira and Microsoft Zira. The Setup Wizard's first step and three documents no longer promise performance that nobody has measured.
- Balanced (Qwen2.5-1.5B, 1.20 GB of model files to download) is now the default preset. A new
NpcRuntimeConfig, the config used when none is assigned, the Setup Wizard and the three sample configs use it, and the wizard recommends it on every machine. Fast (Qwen2.5-0.5B) stays selectable as the option for low-end PCs. A config asset you saved before keeps the preset it has. The Editor warns under 11 GB of RAM for Balanced; that value has not been measured. - The samples' first-run download panel shows what will be downloaded. It lists each missing model with its size, the total and the number of files ("Total download: 1.20 GB (2 files)"), says that the progress bar starts again for each file, and shows "File 1 of 2" during the download. All sizes LocalNPC shows, in the player and in the Editor, are now in decimal units, the same as the Setup Wizard ("569 MB", "1.20 GB");
ModelEntry.FormatBytesandModelEntry.SizeFormattedreturn this format instead of binary units with one decimal ("1065.6 MB"). - The NPC speaks with the Windows system voice.
localnpc_winspeech.dllinPlugins/x86_64uses a OneCore voice, with SAPI 5 as the last fallback; for en-US it tries Microsoft Mark, then Microsoft Zira, then Microsoft David, then any other en-US voice. Nothing is downloaded for the voice. With no voice for the language, the NPC answers in text only and logs one warning. The voice is not emotional, and a sentence that ends with a terminator of the language profile is followed by 300 ms of silence. No Piper voice is included. - Speech-to-text runs in-process. It uses five whisper.cpp 1.9.5 libraries in
Plugins/x86_64(ggml-base.dll,ggml.dll,whisper.dll,ggml-cpu-haswell.dll,ggml-cpu-x64.dll). No.exeis started any more. - The speech model comes from the model catalogue. Download it in Tools > LocalNPC > Model Manager. The file is checked against the size and SHA-256 of its catalogue entry before every load. It is no longer looked up in development folders.
- Text chat keeps working when speech fails to load. The recognizer no longer reports "loaded" with nothing loaded. A missing or damaged speech model, or a missing or blocked library, is reported once through
OnErrorwith a message that contains the sentence "Speech input is off. Text input still works.", and the agent goes toIdle. - The fixed English prompt that was passed to every transcription is removed. Decoding is greedy with no prompt.
- Allow 'unsafe' Code is no longer needed. LocalNPC has no unsafe code, and all of its assembly definitions set
allowUnsafeCodeto false. The Setup Wizard, step 1 (Environment & Hardware), no longer checks the setting, andBuildPreprocessorno longer stops a build when it is off. You can leave the setting as it is. - The QuickStart sample NPC is now Mira, the lamplighter of Hollowmere, with three example exchanges. Before, it was a generic assistant for testing.
- The Shopkeeper and Kiosk sample NPCs now have three example exchanges each. Before, their assets stored them under a key the personality does not read, so they had none. The Kiosk greeting no longer offers exhibit schedules, which the kiosk cannot give.
- The three sample NPCs decline in character. Each sample personality has one more sentence in its system prompt and two example declines in the character's voice. On the default model this reduced the replies that break character or refuse in a generic assistant voice ("as an AI ...", "I can't assist ..."), but did not remove them (from 31% to 14% on the questions we tuned on, and from 49% to 36% on 5 new questions); the Kiosk still does it most. See "Teaching your NPC to decline in character" in the Personality Writing Guide. LocalNPC has no content filter.
- The QuickStart sample NPC speaks with Microsoft Zira, a woman's voice, because Mira is a woman. Before, it used the default voice, Microsoft Mark, a man's voice. On a PC without Zira it falls back to the default voices as before.
- The Kiosk sample listens like the other two samples. It starts in Continuous Voice with the agent's built-in microphone on: click Start Voice, then ask for directions. Before, it started in Push To Talk, where holding the button sent nothing to the NPC, because
PushToTalkControlleris not connected to the microphone in v1.0. The samples' Mode button now skips Push To Talk when noPushToTalkControlleris assigned, andDemoSceneControllerno longer looks one up by itself. The Kiosk greeting names the Start Voice button. Push-to-talk with the microphone is planned for v1.1. - Unity 6000.0 or newer is required.
package.jsonsays"unity": "6000.0", and the Setup Wizard, step 1 (Environment & Hardware), shows a version below 6000.0 as not supported. Before, the package gave a lower minimum than the versions it was tested on. - LocalNPC is tested on Unity 6000.0.85f2, 6000.3.10f1 and 6000.6.8f1. Other Unity 6 versions are not officially tested. On 6000.0 the package was tested in the Editor (EditMode and PlayMode tests, Built-in and URP) and a Windows player of the head demo scene was built and run by hand (the head faces the camera, speaks with a man's voice and moves its jaw, with no error). The minimum was 6000.3 before this test.
- LocalNPC runs on 64-bit Windows only. On any other platform it logs one message that says so, loads no model, calls no native library and does not use the microphone, and the LocalNPC Editor windows show the message at the top. A build for another target, or for 32-bit Windows, still works: it logs one warning that LocalNPC will do nothing on that platform, and the model and plugin checks run only for Windows x64 builds. This was tested with a simulated non-Windows platform, not on a Mac or Linux PC.
- The model download keeps a file that is already there only when it has the exact size of its catalogue entry. A file that is shorter or longer is downloaded again and replaced by the checked download. Before, any file over 1 MB was kept.
- The RAM texts say what was measured. The Balanced model warns under 11 GB of RAM, a value that has not been measured; the Setup Wizard, the Model Manager and the config inspector all use it, and the config inspector gives the one figure there is (about 2 GB used by a game with the Balanced model, on one test PC). The Fast model and the speech model show "Suggested RAM: not measured" in the Model Manager, and Fast gets no RAM warning. The Inspector texts no longer say the player can interrupt the NPC by speaking: only game code that calls
Interrupt()does. - The sample HUD shows "Time to first audio". For a voice turn the clock starts when you stop speaking, and it stops when the first sentence starts to play. The label was "Latency (speech -> audio)".
- Support is by email: localnpcsupport@gmail.com (Troubleshooting, "Getting help"). The docs no longer send you to the repository or to
git lfs pull: when a plugin file is damaged, import LocalNPC again from the Asset Store. The docs say that v1.0 runs on the CPU only. - The sample scenes draw in the Built-in Render Pipeline and in URP. Their capsules, floors and props use the samples' own simple shader (
Samples/SampleShaded.shader, a fixed light, no shadows) instead of URP's Lit material, so they are no longer pink in a Built-in project. HDRP is not supported. - Clearer Setup Wizard texts. Step 1 calls the plugin check "Plugin files" (it was "Git LFS Assets"), and the Audio Latency row is a yellow warning, not a red error: the buffer size is a recommendation. Step 2 says in plain words that LocalNPC can resume an interrupted download. Step 3 says "LocalNPC is ready!" only when the models of the preset are installed; otherwise it says to download them in step 2.
- The Diagnostics window shows a turn above its target in amber, not as a red "BUDGET OVERRUN". The RAM card compares with the preset the agent runs (Fast: 800 MB; Balanced has no RAM target), not always with Fast. Its time to first audio is labelled "(pipeline)": it starts after the end-of-speech wait of about 0.9 s, as the sample HUD's does, but the two use different clocks and can differ.
- The sample HUD shows "MODELS MISSING" instead of "IDLE (Ready for input)" when the models are not installed, a short note under "Time to first audio:", and long NPC names no longer run into the reply text. The Start Voice button is disabled while the models load.
- The NpcAgent Inspector section is called "Interruption", and its tooltips no longer mention barge-in: in v1.0 only your code interrupts the NPC by calling
Interrupt(). The model row of the NpcAgent Inspector has shorter texts that fit a normal Inspector width. - Fewer Console lines. "Assembly reload detected ..." is logged only at the Verbose level, not at every Play, and the microphone start line names "the default microphone" instead of an empty name.
- The models come from Hugging Face only, over a checked connection. LocalNPC downloads the model files from huggingface.co over HTTPS with the server's certificate checked the normal way (before, any certificate was accepted; the SHA-256 check of each file stays). There is no mirror any more: when the download fails, the error names the host and says to check the internet connection. A catalogue entry without a SHA-256 still works with the size check, and logs a warning that only its size is checked.
ModelEntry.mirrorUrlis removed. LocalNPC runs no server of its own. - No voice activity model is downloaded. v1.0 detects speech with the built-in energy VAD and never used the Silero VAD file, so it is no longer in the model catalogue, the Setup Wizard, the Model Manager (no "Voice Activity" tab) or the kiosk build check. The Fast preset downloads 569 MB (was 571 MB); Balanced stays 1.20 GB.
WhisperCppRecognizerandWhisperRecognizerare no longer public. LocalNPC creates the speech recognizer itself; if you need it in your code, useISpeechRecognizer, for exampleNpcAgent.Pipeline.Recognizer.
Removed
LICENSE.mdis removed from the package. LocalNPC is sold on the Unity Asset Store, and the standard Unity Asset Store EULA applies; the package has no licence file of its own. The licences of the third-party parts are inThird-Party Notices.txt, as before.- The "Fetch Dev Model" button is removed. It was in the developer window LocalNPC > Developer > Environment Check. It downloaded a model from the
mainbranch of its repository, not a pinned version, with no SHA-256 check. Get the models with the Setup Wizard or the Model Manager. PiperSynthesizerno longer looks for or startsLocalNPC_TTS.exe. The lookup in development folders and inStreamingAssetsis gone, withPiperSynthesizer.TerminateTtsDaemon(). No LocalNPC code creates aPiperSynthesizer; the NPC voice is the Windows system voice.
Fixed
- The NPC answers "Thank you" and "Bye". A transcript of only "thank you" or "bye" (any case, with or without punctuation) was always dropped as Whisper noise. It is now dropped only when Whisper reports that the turn holds no speech (a no-speech probability of 0.5 or more, or no valid value). "You", "the end", "thanks for watching", "thank you for watching" and "subtitles by", empty transcripts, sound tags such as
[BLANK_AUDIO]and one-character transcripts are still always dropped. The 0.5 threshold comes from one session on one microphone; it has not been measured with fan noise or on other microphones. - No obsolete-API warnings from LocalNPC on newer Unity 6 versions. On Unity 6000.5 and newer, the Diagnostics window finds the scene's agents with
FindObjectsByTypewithout a sort mode, and the sample scenes' controller finds the agent and the subtitle HUD withFindAnyObjectByTypein place ofFindFirstObjectByType; Unity marks the sort-mode overloads andFindFirstObjectByTypeobsolete there. Each sample scene has one agent and one HUD, so the same objects are found. On Unity 6000.0 to 6000.4 the Diagnostics window keeps its call. - Voice turns no longer wait 30 s in steady fan noise. The microphone gain raised steady noise to about the level of speech, so the energy VAD heard speech all the time and a turn ended only at the 30 s limit. The microphone path now scores the audio before the gain, and its threshold follows the room noise (2.5 × the noise floor, never below about -44 dBFS); the gain no longer rises outside speech. No speech is detected in the first 320 ms after the microphone starts, while the noise floor is learned. A turn ends about 0.9 s after the last word (0.94 to 1.10 s in an offline replay of fan recordings; not measured in the app), and a voice turn now ends after 12 s at most instead of 30 s. No Inspector setting changed.
- A short dip in steady noise no longer makes every voice turn run to 12 s. When the noise went quiet for a fraction of a second (130-250 ms, 12-16 dB, as a laptop microphone did in a fan recording), the tracked noise floor fell with it, the returning noise then counted as speech, and from then on each turn ended only at the 12 s limit. The noise floor now falls at most 3 dB per second, so a turn again ends about 1.1 s after the last word in those recordings (offline replay; not measured in the app). When the room really gets quieter, for example a fan is switched off, the microphone needs a few seconds to follow; in that time quiet speech must be a little louder to be heard. No Inspector setting changed.
IsReadyis false after a cancelled prewarm. A cancelledPrewarmAsyncmay have loaded nothing, butIsReadywas true, so code that prewarms only an agent that is not ready (the sample scenes do this) never loaded the models. NowIsReadyis true only after a prewarm completes. A turn after a cancelled prewarm still loads the language model and answers, as before.- The "Reset to Factory Defaults" dialog of
NpcRuntimeConfignames the Balanced preset, the preset it sets. It said Fast. - The Environment Check no longer runs Git. This is the developer window LocalNPC > Developer > Environment Check; the buyer's checks are in the Setup Wizard, step 1 (Environment & Hardware). Its "Git LFS" row ran
git lfs env, so on a PC without Git it showed a failed check for nothing. The row is now "Plugin files": it reads the first bytes of the eight libraries inPlugins/x86_64and fails only when one is a Git LFS pointer file, with the advice to import LocalNPC again from the Asset Store. It no longer scans the rest of yourAssetsfolder, and no LocalNPC script starts a process. - Loud microphone input no longer folds over. A sample that the microphone gain lifts above full scale used to come out quieter (just over 1.0 became 0.5), which distorted loud speech. The limiter now leaves samples up to 0.8 unchanged and saturates smoothly above that: a louder sample never comes out quieter, and the output stays within 1.0.
- Sound tags are removed from transcripts. When the speech model marks a sound at the start or end of what you said, for example "[Music] Hello, who are you?" or "Hello. (audience laughing)", the tag is removed and only "Hello, who are you?" or "Hello." is shown and passed to the language model. Brackets in the middle of a sentence are kept. A transcript made only of tags is still ignored as noise.
- The package no longer contains the tests or the development log. The
.unitypackageand the UPM tarball leave outTests/(the EditMode and PlayMode tests and their two assembly definitions) andDEVELOPMENT-LOG.md, which held links to folders on a developer's PC. They stay in the LocalNPC repository. Your project now gets three LocalNPC assemblies: Runtime, Editor and Samples. - The
.unitypackagenow includes the documentation. The guides are inAssets/LocalNPC/Documentation, where the Project window shows them, and the links of the README open them. Before, the.unitypackagehad no docs and the README's links to them were broken. The UPM package keeps them inDocumentation~. Links in the docs to folders on a developer's PC are removed. - Signed native libraries load. A shipped DLL that you sign with your own Authenticode certificate is no longer refused as "not the build this package was tested with". The pinned SHA-256 now leaves out the parts signing changes (the PE CheckSum, the Certificate Table entry and the certificate table); a change to any other byte is still refused. The pinned values of all eight libraries changed with it.
- The jaw of
AmplitudeLipSyncfollows every sentence. The NPC's voice plays on two AudioSources, one sentence on each in turn, andAmplitudeLipSynclistened only to the first. So the mouth stopped moving on every second sentence. It now listens to both. Tested with a test tone, not with a rigged character. - StopAfterSentence no longer plays one extra sentence. The next sentence was already scheduled when you stopped, so it still played. Now the sentence that is playing finishes and nothing after it starts.
SpeechAudioQueue.Initializekeeps the second AudioSource. CallingInitializefrom your own script removed it, and then only the last sentence of a reply was heard.- The second AudioSource follows setting changes. Changes you make to the NPC's AudioSource after the scene starts (volume, pitch, 3D blend, mixer group, distances, rolloff, doppler, spread) now apply to every sentence, not only to every second one. A change made while a sentence is already scheduled applies from the next sentence.
- Several callers that prewarm at the same time (two NPCs in a scene, or an agent and a scene controller) now share one load of the language model. Before, the sample scenes logged "A model is already loaded in this process" and a second NPC stayed in
Error. - Text chat works again after the models unload while the language model is still loading. Destroying an NPC during its load with
IdleUnloadSeconds0, callingLocalNpc.UnloadAll()during a load, or stopping and starting Play quickly with domain reload off left the model loaded where nothing could use it, and every later load failed with "A model is already loaded in this process" until the game or the Editor restarted. Now that model is freed when its load ends, and the next load waits for that. A new NPC that starts during the idle unload no longer waits for it. - Numbered lists in a reply are no longer split into sentences of only "1.", "2." and so on. A list marker at the start of a line ("1.", "- ", "* ", "+ ") now stays with the item after it, and a line break inside a sentence becomes one space.
maxReplySentencesnow limits the reply. A reply is cut after the Nth whole sentence (N =maxReplySentences) and the rest of the generation is stopped.- A short first sentence does not count toward
maxReplySentences. A first sentence of at most two words and 12 characters, such as "Sure!", is spoken, shown and kept in the reply but not counted, so a reply can have one sentence more. Only the first sentence of a reply is treated this way. - Importing the Kiosk sample no longer breaks every player build. The build checked every
NpcRuntimeConfigin the project, so the Kiosk config (StreamingAssets mode, models not copied yet) stopped the build of any scene. Now a build checks only the configs used by anNpcAgentin a scene of the build, inactive objects included, and fails with the same message as before. A config that no scene of the build uses is no longer checked at build time, for example one you load or assign at runtime, or one on a prefab you spawn at runtime; the build logs a warning for each such config whose models are missing. Entering Play Mode is not affected by this check. LocalNPC_BuildManifest.jsonis valid JSON. When the last file inStreamingAssets/LocalNPCwas a.metafile, the build manifest had a trailing comma after the last model entry, and JSON readers refused the file. The format and the field names are unchanged.LocalNPC_BuildManifest.jsonis also valid JSON when anNpcRuntimeConfigcannot be loaded. When the last runtime config found in the project could not be loaded, the manifest had a trailing comma after the lastconfiguredRuntimePresetsentry. The format and the field names are unchanged.- The Setup Wizard's "Pin 2.6.1 in manifest.json" button no longer breaks
Packages/manifest.json. It used to write the Inference Engine line with a trailing comma, so the manifest was invalid JSON when that entry was the last one, and it changed the line endings of the whole file. It now changes only the version, keeps every other byte and the line endings, does not write the file when the version is already 2.6.1, and leaves a manifest that is not valid JSON unchanged with a warning. - The Setup Wizard's last step opens the QuickStart sample. Its button, now Open QuickStart Sample Scene, used to open a development scene that is not in the package and always showed "Scene Not Found". It now opens
01_QuickStart.unityfromAssets/LocalNPC/Samples(the.unitypackage) or fromAssets/Samples/LocalNPC(Package Manager samples), after asking to save modified scenes. When the sample is not in the project, the wizard says how to import it. - No red error on the first Play before the models are downloaded. When a model is not installed yet, the prewarm now logs one warning that names Tools > LocalNPC > Setup Wizard and the first-run panel, instead of the red error "Pipeline prewarm failed ... ModelMissing".
OnErrorstill getsModelMissing, and a prewarm after the download loads the agent in the same Play. A damaged model or a library that fails to load is still a red error. A failed prewarm now reachesNpcAgent.OnErroronce; before, the agent passed on the pipeline's error and then reported "PrewarmAsync failed" as well. - An NPC speaks on a PC without a voice of its exact language region. An en-US NPC on a PC that has only English UK voices (or en-IN, en-AU, ...) used to answer in text only. When no voice of the NPC's own language tag is installed, any voice of the same main language is now used, before the SAPI 5 fallback. With no voice at all, the one warning now says which language was looked for and where to add a voice (Settings > Time & language > Speech > Manage voices > Add voices), and the sample HUD shows "No voice found - showing text only".
Notes
- Restart Unity after replacing the package DLLs: the speech-to-text libraries stay loaded for the life of the process.
- The environment variable
LOCALNPC_WHISPER_CPU_BACKENDis set by the package inside its own process and is used internally. - Measured for the speech-to-text step alone, on one laptop (Intel Core i7-8750H, 15.8 GB RAM, Windows 11 10.0.26300),
tiny.enmodel, 4 threads, haswell CPU library, on battery, one or two runs per figure: an 11 s clip in 0.61 to 1.07 s, a 3 s clip in 0.62 to 0.90 s; the loaded model costs about 135 MB of working set and about 650 MB of private bytes. The time from end of speech to first audio has not been measured.
[1.0.0] - 2026-09-25
Milestone: Public API Freeze (Step 44)
The public API surface under LocalNPC namespace is officially frozen per Developer Build Guide v4.0 §7.1. All public types, properties, methods, and event signatures are locked. Future changes will strictly maintain backward compatibility or require major version increments.
Added
- Core Agent Surface (
LocalNPC.NpcAgent):- High-level MonoBehaviour interface for character embodiment and conversational turns.
- Lifecycle state tracking (
State,IsReady) and cancellation-aware async operations (PrewarmAsync,SayAsync,SpeakDirectAsync). - Runtime conversational control (
StartListening,StopListening,Interrupt,ResetConversation,SetPersonality). - Reactive turn events:
OnStateChanged,OnUserTranscript,OnReplyChunk,OnSentenceSpoken,OnReplyComplete,OnError.
- Top-Level Static Facade (
LocalNPC.LocalNpc):- Unified package access point for model provisioning and resource management (
EnsureModelsAsync,AreModelsReady,UnloadAll,Settings). - Global
LocalNpcSettingsfor runtime configuration defaults and logging verbosity.
- Unified package access point for model provisioning and resource management (
- Contract Error Handling (
LocalNPC.NpcErrorCode&LocalNPC.NpcError):- Standardized error codes conforming to §7.1 with zero unhandled exceptions escaping across public boundaries at runtime.
- Multilingual Architecture Seam (
LocalNPC.LanguageProfile):- ScriptableObject driven language profiles with public extensible interfaces (
IPhonemizer,ITextNormalizer).
- ScriptableObject driven language profiles with public extensible interfaces (
- Productisation & Samples (
LocalNPC.Samples):DemoSceneControllerandSubtitleHudsupporting First-Run model provisioning, keyword event hooks, and a Push-to-Talk mode. Push-to-talk is not connected to the microphone in v1.0 (see [Unreleased]); it is planned for v1.1.- Three complete sample scenes:
01_QuickStart,02_Shopkeeper,03_Kiosk.
- Build Pipeline Verification:
BuildPreprocessorandBuildPostprocessorfor automated 64-bit verification, unsafe code pre-checks, SHA-256 verification of the native libraries, and build manifest generation.
- Documentation Suite (Step 45):
- Ten comprehensive documentation guides published under
Documentation~/and mirrored todocs/: Quick Start, Requirements, Personality Writing Guide (<200 tokens, exemplars), Model Presets, API Reference, Performance Tuning, Lip Sync, Shipping, Offline Kiosks, Language Architecture, and Troubleshooting Playbook.
- Ten comprehensive documentation guides published under
- Package Validation & Distribution (Step 46):
- Implemented
PackageExporter(File #77) for package staging,_Devstripping, manifest validation,.unitypackageexport, and UPM.tgztarball creation with batchmode CI execution (ExportPackageBatch). - Configured the native plugins
llamalib_win-x64_avx2.dllandllamalib_win-x64_noavx.dllforx86_64Windows Standalone and Editor execution exclusively. The earlier placeholderLocalNPC_Native.dllis removed. - Published
Third-Party Noticesfor the open-source backends (Llama, Whisper, Piper, Silero). The licence file of the package that came with it was removed before release (see [Unreleased]); LocalNPC itself is under the standard Unity Asset Store EULA.
- Implemented
Contract Guarantees
- Every public asynchronous method accepts a
CancellationToken. - No runtime exceptions cross the public boundary into game code; all operational errors dispatch through
OnError. - Zero vendor types (Llama, Whisper, Piper, Silero, ONNX, Tensor) exposed in the public
LocalNPCnamespace. - No platform-specific types or compile directives exposed in public contracts.