diff options
| author | Bobby <[email protected]> | 2026-04-22 14:32:03 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2026-04-22 14:32:03 +0530 |
| commit | bbe9d34700995ba1644d726743dbb61144052bd1 (patch) | |
| tree | bee0455edb7023d08b348022672ec2c294f2579c | |
| parent | 87f4e51a2804d0788c8cd1fcde56923d19d0e06c (diff) | |
| download | hollowdark-main.tar.xz hollowdark-main.zip | |
| -rw-r--r-- | content-system/registry/registry.ts | 14 | ||||
| -rw-r--r-- | content-system/registry/singleton.ts | 25 | ||||
| -rw-r--r-- | loading/content.ts | 46 | ||||
| -rw-r--r-- | routes/+layout.svelte | 4 | ||||
| -rw-r--r-- | routes/+page.svelte | 6 |
5 files changed, 88 insertions, 7 deletions
diff --git a/content-system/registry/registry.ts b/content-system/registry/registry.ts index 38f0a91..6910cab 100644 --- a/content-system/registry/registry.ts +++ b/content-system/registry/registry.ts @@ -62,18 +62,26 @@ export class ContentRegistry { } } +/** Per-chunk callback used to advance a progress bar as loading proceeds. */ +export type ChunkProgressCallback = (loaded: number, total: number) => void + /** * Populate a fresh registry from the supplied manifest. Fetches every * chunk whose id begins with a world-content prefix; ignores unknown * prefixes so the registry can grow without breaking older clients. + * Chunks load in parallel; the callback reports completion order, not + * start order. */ export async function populateFromManifest( manifest: ContentManifest, - baseUrl: string + baseUrl: string, + onProgress?: ChunkProgressCallback ): Promise<ContentRegistry> { const registry = new ContentRegistry() - const entries = Object.entries(manifest.chunks) + const total = entries.length + let loaded = 0 + await Promise.all( entries.map(async ([chunkId]) => { const { data } = await loadChunk(chunkId, manifest, baseUrl) @@ -84,6 +92,8 @@ export async function populateFromManifest( } else if (chunkId.startsWith('world/institutions/')) { registry.addInstitution(data as unknown as InstitutionContent) } + loaded += 1 + onProgress?.(loaded, total) }) ) diff --git a/content-system/registry/singleton.ts b/content-system/registry/singleton.ts new file mode 100644 index 0000000..d8a556e --- /dev/null +++ b/content-system/registry/singleton.ts @@ -0,0 +1,25 @@ +import type { ContentRegistry } from '@hollowdark/content-system/registry/registry' + +let instance: ContentRegistry | null = null + +/** Record the registry populated during session startup. */ +export function setContentRegistry(registry: ContentRegistry): void { + instance = registry +} + +/** + * Access the shared content registry. Throws if called before the + * loading pipeline has populated it — simulation code should never run + * until initial load is complete. + */ +export function getContentRegistry(): ContentRegistry { + if (instance === null) { + throw new Error('Content registry not initialised. Initial load must complete first.') + } + return instance +} + +/** True once the registry has been populated. */ +export function hasContentRegistry(): boolean { + return instance !== null +} diff --git a/loading/content.ts b/loading/content.ts new file mode 100644 index 0000000..d3181fa --- /dev/null +++ b/loading/content.ts @@ -0,0 +1,46 @@ +import { fetchManifest } from '@hollowdark/content-system/loader/loader' +import { populateFromManifest } from '@hollowdark/content-system/registry/registry' +import { setContentRegistry } from '@hollowdark/content-system/registry/singleton' +import { loadingProgress } from '@hollowdark/loading/progress' + +/** + * Run the real initial-load pipeline. Fetches the content manifest, + * walks every chunk into the shared registry, and reports progress to + * the loading store so the initial-load screen's bar moves in real + * time. Falls back to whatever is cached when offline. + * + * `baseUrl` is the app's base path — empty string in local dev, the + * hosting sub-path under GitHub Pages. + */ +export async function runInitialLoad(baseUrl: string): Promise<void> { + loadingProgress.set({ + percentage: 0, + currentMessage: 'Preparing your reading space', + phase: 'loading' + }) + + const manifest = await fetchManifest(baseUrl) + const chunkCount = Object.keys(manifest.chunks).length + + if (chunkCount === 0) { + setContentRegistry( + await populateFromManifest(manifest, baseUrl, () => {}) + ) + loadingProgress.set({ + percentage: 1, + currentMessage: 'Preparing your reading space', + phase: 'complete' + }) + return + } + + const registry = await populateFromManifest(manifest, baseUrl, (loaded, total) => { + loadingProgress.set({ + percentage: loaded / total, + currentMessage: 'Preparing your reading space', + phase: loaded === total ? 'complete' : 'loading' + }) + }) + + setContentRegistry(registry) +} diff --git a/routes/+layout.svelte b/routes/+layout.svelte index 0cf4c43..0d84d4d 100644 --- a/routes/+layout.svelte +++ b/routes/+layout.svelte @@ -1,12 +1,12 @@ <script lang="ts"> - import { base } from '$app/paths' + import { assets } from '$app/paths' import AudioPlayer from '@hollowdark/lib/audio/AudioPlayer.svelte' import { highContrast, reduceMotion } from '@hollowdark/lib/accessibility/state' import { textSize, type TextSize } from '@hollowdark/lib/reading/state' let { children } = $props() - const titleTrackSrc = `${base}/audio/title/piano-relaxing.mp3` + const titleTrackSrc = `${assets}/audio/title/piano-relaxing.mp3` const ALL_TEXT_SIZE_CLASSES: readonly string[] = [ 'text-size-small', diff --git a/routes/+page.svelte b/routes/+page.svelte index babf994..debc068 100644 --- a/routes/+page.svelte +++ b/routes/+page.svelte @@ -1,10 +1,10 @@ <script lang="ts"> import { onMount } from 'svelte' import { goto } from '$app/navigation' - import { resolve } from '$app/paths' + import { assets, resolve } from '$app/paths' import BeginScreen from '@hollowdark/lib/screens/BeginScreen.svelte' import InitialLoadScreen from '@hollowdark/lib/screens/InitialLoadScreen.svelte' - import { runStubInitialLoad } from '@hollowdark/loading/stub' + import { runInitialLoad } from '@hollowdark/loading/content' import { detectBeginState, type BeginState } from '@hollowdark/loading/session' import { hasCompletedInitialLoad, @@ -18,7 +18,7 @@ onMount(async () => { if (!hasCompletedInitialLoad()) { - await runStubInitialLoad() + await runInitialLoad(assets) markInitialLoadComplete() } beginState = await detectBeginState() |
