跳到內容

資料來源與資源載入

Core 讀取資料、解析素材路徑並管理載入與清理。它保留原資料格式;Vega、Cassiopeia、Home Spot 分別負責自己的畫面。本頁先讀取一個真實 JSON 和圖片,劇情播放見 Vega 教程。瀏覽器使用已託管的 https://haneoka.org/embed/core.js,無需安裝 npm。

開啟完整 promenade.json。它儲存標題、背景路徑和一行文字;garden.svg是對應的原創圖片。下面的頁內示例選擇「HTTP JSON」並載入,即可看見資料。隨後點「解析資源 URL」取得圖片地址,或「讀取資源位元組」檢查實際內容。這裡讀到的 lines 資料不是 Vega 可播放檔案,轉換見第 3 步。

修改 JSON 參數,然後點擊載入。模組和請求只在點擊後啟動;輸出包含實際回應與傳輸紀錄。

語言

正在準備範例…

檢視範例程式碼
import { createEmbedLoader, httpDataSource } from "https://haneoka.org/embed/core.js";
const loader = createEmbedLoader({
source: httpDataSource({ url: "https://docs.haneoka.org/examples/promenade.json" }),
locale: "fr",
});
const data = await loader.load();
const imageUrl = await loader.resourceUrl(data.background);
// 消費者使用完這個地址後,再 await loader.dispose()。

HTTP 相對素材以配置的 JSON 所在目錄為基準,重定向不改變這個基準;顯式 assetsBase 可覆蓋它。resourceUrl 取得地址,resourceBytes 讀取實際位元組。source/locale/resourceKey 等示例面板欄位會轉換成實際 factory,其中 resourceKey/resourceField 是此演示選擇素材的欄位,完整 SDK 引數見後面的表。

分別儲存 promenade.json 與 garden.svg。開啟完整檔案讀取網頁,先選擇 JSON,再選擇圖片,點選「載入所選檔案」。你會看見標題 Une promenade、原創庭園圖片及實際圖片位元組數。關閉讀取器會先移除圖片,再銷燬 loader 和它的 Blob URL;可以重新選擇檔案再載入。

將下面程式碼儲存為 UTF-8 的 index.html 即可保留這個完整專案;本地 HTTP 開啟方法見快速開始。目錄為 index.html、promenade.json、garden.svg 三個檔案。JSON 中 background 是素材鍵,檔案對映以這個鍵指向你實際選擇的 File,也支援合法 Unicode 路徑。

分別選擇 JSON 和所需素材。這裡對映一張圖片;多檔案專案為每個宣告的素材鍵及模型清單引用檔案提供對應的 File。

3. 把本頁的通用資料轉換為劇情

Section titled “3. 把本頁的通用資料轉換為劇情”

promenade.json 的格式是本頁的資料讀取例,不是 AdvStory。Vega 要求 commands 陣列。對這份明確的 lines 格式,可以在讀取 data 後建立:

const storyDocument = {
localization: { locales: [data.language], defaultLocale: data.language },
commands: [
{ command: 25, background: { url: data.background } },
...data.lines.map(line => ({ command: 2, targetName: line.speaker, text: line.text })),
],
};

把 storyDocument 作為 mountStory 的 document,並把 assetsBase 指向同一素材目錄;完整可儲存劇情網頁與載入步驟在 Vega。選擇的 JSON 已是完整 AdvStory 時,直接讀取它,不再做這個特定 lines 轉換。decode 校驗/轉換實際資料,TypeScript 泛型只描述期望型別。

在頁內示例選「本站資料」,載入公開歌曲後解析 jacketUrl。介面卡與消費者均可使用託管入口:

import { createEmbedLoader, haneokaDataSource } from "https://haneoka.org/embed/core.js";
const loader = createEmbedLoader({
source: haneokaDataSource({ resource: "songs", id: "100070" }),
server: "intl", locale: "en",
});
const song = await loader.load();
const imageUrl = await loader.resourceUrl(song.jacketUrl);
// 先結束消費者,再 await loader.dispose()。

公開讀取無需帳號或 release。server 選擇素材目錄,locale 選擇語言上下文,返回資料保留源提供的多語欄位。source.assetsBase 預設是 API origin;資源基於它解析,顯式 loader.assetsBase 可覆蓋。repeat load 會再次讀取當前資料。自有物件使用 memoryDataSource,選中的 File 使用 fileDataSource,更多簽名和傳輸限制都在下方完整參考。


欄位型別/必填/預設作用、組合和錯誤
source必填 DataSource<T>提供 load(context),每次 load 呼叫;可選 source.assetsBase 為素材目錄,dispose 清理一次。資料格式應符合消費宿主。
server可選 string,undefined原樣傳給 source/resolver;本站 adapter 預設intl並用公開客戶端校驗 slug,與語言獨立。
locale可選 string,en原樣保留 fr/pt-BR 等作者語言;本站透過 Accept-Language 協商支援語言。
assetsBase可選 string,source.assetsBase→無覆蓋 source base,絕對 HTTP(S) 目錄,不含 query/fragment,補斜線;構造時非法 TypeError,無base相對key URL構造失敗。
resolveResource可選 (key,DataContext)=>string/URL/Blob 或其Promise,預設原key完整對映key,相對結果基於base;拒絕即資源失敗,Map缺key不回落網路。
fetcher可選 (Request)=>Promise<Response>,預設fetch接收cors、配置headers/credentials/signal的Request,檔案和資源共同使用;媒體元素有獨立載入器。拒絕傳遞為操作失敗。
credentialsomit/same-origin/include,omit跨域帶cookie需服務允許origin與credentials;非法值由Request拒絕。
headers可選 HeadersInit,無共用頭,source逐次header覆蓋同名值;本站以locale設Accept-Language,校驗遵循Fetch。
maxBytes可選正safe integer,67108864每項解碼JSON/資源bytes預算,不是總場景/cache/URL預算。構造非法RangeError,超預算read RangeError(本站包裝response_too_large)。
onListenerError可選 (unknown)=>void,忽略接收observer異常,自身異常隔離,不影響操作結果。

構造無signal/timeout/decode/自動重試cache選項;使用逐次signal、source decoder和宿主策略。resourceUrl僅解析,不下載,也不約束之後媒體元素的位元組量。

Factory必填可選/預設路徑與校驗
memoryDataSource(data)任意T無返回同一值/物件identity,不復制校驗,無預設素材目錄。
httpDataSource({url,decode?})絕對HTTP(S) string/URLdecode(unknown)=>T,預設JSONfactory校驗URL/protocol,base為配置URL目錄;redirect不改變base。讀取遵循signal/budget,JSON/decoder失敗拒絕。
fileDataSource(file,decode?)File或Blobdecoder同上無網路base,實際Blob bytes受預算/進度控制,壞JSON/decoder拒絕。
fileResourceResolver(files)ReadonlyMap<string,Blob>無Unicode完整key字面查詢,不規範化;缺項Error。URL生成owned BlobURL,bytes直接讀Blob。
haneokaDataSource(options)resource:string下述欄位當前公開目錄,不填帳號/release。

本站source全部欄位:resource 使用manifest資源語法;id?:string 有值取entity,省略取index;view?:string 選manifest投影;apiBase?:string 預設 https://haneoka.org/api/v1/,絕對HTTP(S)目錄不含query/fragment;decode? 校驗index/entity,預設JSON值。語法/不存在等load錯誤沿客戶端。source預設素材base是API的origin根,可由loader.assetsBase覆蓋;server/locale來自loader。

自定義 source/resolver 的完整 context

Section titled “自定義 source/resolver 的完整 context”

DataSource<T> 包含 load(context):T|Promise<T>、可選 assetsBase?:string、dispose():void|Promise<void>。loader銷燬時清理一次並等待,cleanup失敗拒絕dispose;擁有資源的source按單loader所有權使用。

DataContext欄位型別含義
server可選string原樣registry。
localestring作者語言或預設值。
signalAbortSignal當前操作取消,底層工作應跟隨。
fetcher(Request)=>Promise<Response>配置後的傳輸。
maxBytesnumber有效解碼預算,自定義解析也應遵守。
progress({loaded:number,total?:number})=>void實際位元組,未知總量省略total。

Resolver同步/非同步返回string、URL、Blob。絕對HTTP/HTTPS/Blob/data保留origin,相對基於assetsBase,/開頭用origin根;其他protocol TypeError,不猜SSR/頁面base。

const source = {
assetsBase: "https://author.example/project/",
async load(context) {
context.signal.throwIfAborted();
const response = await context.fetcher(new Request("https://author.example/project/story.json", { signal: context.signal }));
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json(); // 接入自己的格式校驗和預算讀取。
},
dispose() { /* 回收source擁有的資源 */ },
};
const loader = createEmbedLoader({ source, locale: "pt-BR", resolveResource: key => key });
成員引數/結果生命週期
localereadonly string有效語言。
serverreadonly string/undefined顯式server,adapterfallback前。
disposedreadonly booleandispose開始即true。
load(options={})可選signal,Promise<T>每次獨立source操作,key為$data。
resourceUrl(key,options={})必填string,可選signal;Promise<string>不下載,每個Blob複用一個URL直到銷燬。
resourceBytes(key,options={})key/可選signal;Promise<Uint8Array>status/budget/progress真實讀取。
subscribe(listener)必填(event)=>void;返回unsubscribe後續事件,不重放;已銷燬拋Error。
cancel()void取消當前全部操作,loader可重用。
dispose()共用Promise<void>立即禁止新工作、abort、revoke、disposed事件、清監聽、source清理一次;冪等,不能重用。

忽略signal的source也不能遲到ready/progress覆蓋已取消操作;底層source仍應主動停止。cancel可繼續,dispose結束loader。先銷燬consumer,再撤銷loader擁有的URL;作者自行建立的URL自行管理。

type欄位時機
start/readyoperation:number,key:string開始/成功。
progressoperation/key/loaded:number/total?:number實際解碼位元組,記憶體或僅URL無自動bytes進度;壓縮或未知length不填total。
error/cancelledoperation/key/error:unknown失敗/取消。
disposed僅type銷燬,銷燬後的取消錯誤不繼續發出。

operation按loader增長,key為$data或原資源名。observer異常不拒絕操作,併發獨立、不自動重試或去重;演示只保留32條顯示記錄,不改變SDK事件流。

EmbedHttpError(status,url) 擴充套件Error,帶name/message/status/url。URL/base/protocol非法TypeError,預算RangeError,JSON SyntaxError,作者source/resolver/decode原錯誤保留。本站保留ApiClientError,預算為response_too_large及HTTPstatus,預設不可重試。abort拒絕signal.reason,通常AbortError/TimeoutError。dispose後呼叫為Error,sourcecleanup失敗拒絕dispose。

createHaneokaBranding(document,options={}) 在官方core facade和包/branding入口可用。document必填DOM Document;corner?:top-left/top-right/bottom-left/bottom-right,預設top-left。返回HTMLAnchorElement,不自動append,不請求影象。宿主在有定位的完整容器角落懸浮append,保留48px觸控區域,清理時remove。連結固定為 Haneoka,_blank/noopener、原inlineSVG、48px觸控與focus;可視embed自動管理,data-only core匯入不碰DOM。