Neocortex
IntegrationsWeb SDK

Quiz

Run a spoken quiz, game show or test on your page with a character as host

Experimental, Team plan

The request and response shape may change.

A character hosts a run of a question set. Ordering, hints, judging and scoring happen on the server; the page shows the scene and forwards what the player says. Sets are authored in Question Sets; how a run works is in Web API Quiz.

The host must be in characters. Restrict playable sets with questionSets (default: all your team's sets).

Element

<neocortex-quiz endpoint="/api/neocortex" character-id="host-id" question-set-id="set-id" voice></neocortex-quiz>

Options, typed and spoken answers, hint, pass, progress and leaderboard are built in. state is idle, playing or finished; nx-turn and nx-finished let you follow along.

QuizAgent

import { QuizAgent } from "@neocortex-link/web/client";

const quiz = new QuizAgent({ endpoint: "/api/neocortex", characterId: "host-id", questionSetId: "set-id", voice: true });

quiz.on("hostLine", ({ line }) => subtitles.show(line.text));
quiz.on("questionChanged", (question) => ui.showQuestion(question));
quiz.on("leaderboardChanged", (standings) => ui.showScores(standings));
quiz.on("finished", () => ui.showResults(quiz.leaderboard));

startButton.onclick = () => {
  quiz.primeAudio();
  quiz.begin();
};
Player didCall
Clicked an optionchoose(optionId)
Spokesay(transcript)
Typedsay(text, { typed: true })
Skipped or timed outpass()

Hints, repeats and stopping are just words: say("Can I have a hint?"). lastIntent says how the host read it.

Voice answers

Open the mic after the host finishes, when it expects something:

const mic = new AudioReceiver();

mic.on("recorded", async (wav) => {
  const { response } = await quiz.client.transcribe({ characterId: "host-id", audio: wav });
  if (response.trim()) quiz.say(response.trim());
  else mic.start();
});

quiz.on("hostFinished", (turn) => {
  if (turn.expecting !== "nothing") mic.start();
});

Don't send an empty transcript as pass(). A pass means the player chose to skip.

Scene timing

questionChanged fires after the host has read the question. To show the scene as the question line starts, and preload the next one:

let next = null;
quiz.on("turn", (turn) => (next = turn.question ?? null));
quiz.on("hostLine", ({ line }) => line.role === "question" && next?.keyword && scene.show(next.keyword));
quiz.on("upcoming", ({ keyword }) => keyword && scene.preload(keyword));

Several players

quiz.begin([{ id: "alex", displayName: "Alex" }, { id: "maya", displayName: "Maya" }]);
quiz.chooseAs("alex", optionId);
quiz.sayAs("maya", transcript);
quiz.passAs("maya"); // their timer ran out

The host waits until everyone has answered; pending and answered track who. Timers are yours. Up to 10 players.

State and errors

On the agent: question, progress, expecting, leaderboard, lastResult, attempt, attemptsLeft, hintGiven, isFinished.

  • creditsExhausted fires before error when the team is out of credits.
  • An answer after the run ended replays the closing turn and fires finished.
  • Input before begin() or after the end fires inputDropped.
  • resync() restores standings and expecting after a dropped connection. Runs are not kept across reloads.

On this page