chaipat.cc, the ask-me-anything site
chaipat.cc is the site you are reading: a portfolio you search instead of scroll. You can find a project, open its live site, inspect its source or learn about it, as well as ask about Chaipat, his work, his skills or this site itself. Its question view answers like a search engine does: a short answer on top, the sources under it, a knowledge panel beside it, and tabs for images, the SPARQL queries behind the answer and a timeline. A graph view draws the whole graph and its ontology as a network to walk through. He started it in April 2026 and works on it continuously; it is the front door of the chaipat.cc research network.
The knowledge graph supplies facts about his work, and the wiki supplies explanations. Factual answers can be checked in the SPARQL tab, where the queries used and their rows are shown. Finding an entity and choosing an action on it uses the same graph, without turning every navigation request into a factual answer.
History
The site grew out of the personal site he started in his first year at university, in 2022. It has been rebuilt many times on top of that first version, and parts of the old codebase are still in it. The present version, an ask-me-anything page over a knowledge graph, began in April 2026; the wiki, the timeline, the graph view and the time questions came after.
He uses AI coding assistants as tools in that work. He decides what the site does and how it looks, and every change goes through the same tests in a real browser before it is published. The graph-backed factual answers are read with SPARQL; explanations can also quote the wiki.
How a question is answered
Before any question is asked, the graph is loaded and the reasoner adds what the ontology implies (see Reasoning), so every step below works on the stated facts and the inferred ones together. A typed question then goes through one pipeline, the question engine:
- Understand. Entity linking finds the things the question names (projects, skills, roles, games, techniques) by their names, short names and aliases, and the question is sorted into a kind: a list, a how or why question, a definition, a question about a period of time, a question about him, or a question about this site. After planning the original question, the page can try a spelling fallback using Damerau–Levenshtein edit distance against the site's vocabulary. A correction that finds more is applied with Showing results for …; otherwise it is only suggested.
- Retrieve. Candidates come from two places at once: the graph neighbours of what was named, and passages of the wiki ranked with BM25 by the wiki full-text search. Some neighbours exist only through reasoning: "where has he used BM25?" follows one inferred relation, deals with, instead of six specific ones.
- Fuse. The candidate lists are merged with reciprocal rank fusion, weighted by the kind of question, and key work is nudged ahead of side projects.
- Answer. Facts and lists come from SPARQL over the graph, inferred facts included, and the SPARQL tab says how many rows came from reasoning; how and why come from the wiki section that covers it; "what is X" comes from Wikipedia next to what he did with X.
Questions about time are answered from the time data: "this year", "two months ago", "since last year", "in March 2025" or "21 Oct 2024 – 1 May 2025" become a range of dates, and a work counts when it had commits on a day inside it, read from the months of work kept for every repository.
Finding entities and choosing resources
The shared catalog in src/resources.js turns the loaded graph into records for every typed entity except the profile: names, short names and aliases, types, descriptions, outgoing relationships and available resources. The verified product names Wordplay, Graph Laboratory and Project SKY // Lab are aliases in the graph, not special cases in the query planner.
Every catalog entity has an about resource at its local wiki address, even without a written article. A live resource exists only for an explicit cj:liveUrl, and source comes from cj:repository. A general cj:url remains a related link: a publication or store listing is not automatically a live app. External actions accept only HTTP(S) URLs without credentials.
Resource selection follows the planner's task: navigation prefers live, source requests prefer the repository, and learning or discovery prefers about. Missing live or source resources fall back to about; the other available actions stay separate. Navigation and resource selection are deterministic local operations, independent of any model. Optional model augmentation can help explain eligible factual questions using the graph and wiki, but does not choose or rewrite a navigation destination. The catalog does not parse question text or contain per-project query rules. npm run build:wiki emits the same records under entities in the search index while preserving its article passages; the runtime graph remains authoritative.
One answer and its evidence
For supported focused questions, src/answer.js composes one answer from graph facts, a selected passage in the focused article, or a Wikipedia extract. The sources identify evidence actually used; related entities, including technologies shown in the knowledge panel, are not automatically citations. The interface keeps about/live/source actions separate from descriptive prose rather than repeating the description or stack beneath it. Answer-wide actions require a focused entity or explicit personal/site overview; a count does not promote its first matching project into a button or knowledge panel. Lists and comparisons keep individual result links without presenting one result as the destination for the whole answer. Optional model augmentation preserves an existing local answer and its authoritative citations, including when the API returns cached data.
Algorithm, knowledge, wiki, ontology and graph resources must stay current together. npm run build:knowledge rebuilds GitHub and time data before the wiki graph, evidence and index, then writes data/knowledge-state.json. The manifest uses deterministic SHA-256 hashes and portable repository-relative paths, not Git timestamps. It covers relevant code (including the answer and resource modules), schema, graph and wiki sources and the generated artifacts. Validation recomputes the state and expected artifacts without writing, rejecting code/schema drift, missing required sources and stale passage text even when the catalog is current. Scheduled graph and Wikipedia refreshes commit the manifest with dependent outputs, and deployment rejects stale state before building pages.
Hashes establish byte freshness, not truth or semantic agreement. Changes to behavior require review of the affected component explanations and graph descriptions; generators do not invent prose or demand unrelated documentation edits. The component implementation digests cover declared source files, while the manifest also covers shared dependencies.
The knowledge graph
The graph is written in RDF Turtle and described by a small OWL ontology of its own (the cj: vocabulary): the same kind of knowledge graphs he builds in his research, pointed at his own work. It lives in four files:
| File | What it holds |
|---|---|
me.ttl | Written by hand: roles, studies, key projects, and the parts of this site |
github.ttl | Generated from his GitHub repositories: dates of first and last commit, commit counts, languages, themes and how prominent each work is |
wiki.ttl | Drawn from the wiki: the techniques, datasets, services, formats and games each article mentions |
time.ttl | Generated from the commit histories: the years of his work, and every work's months of work with their commits and days |
The Turtle parser reads them and the SPARQL engine queries them, both in the browser and in the build scripts, so a page, its answer and the CV can never disagree. Before every deploy the graph is validated against the ontology, and the fact check confirms that every fact taken from an article is supported by that article.
Reasoning
The ontology is not only a rulebook. When the graph loads, the reasoner applies it, a small form of RDFS and OWL reasoning: subclasses (every project is a work), subproperties (implementing a technique or reading a file format both mean the work deals with that concept), symmetric properties (related works go both ways) and inverse properties (a component of this site means this site has that component). It repeats until nothing new follows. The answers therefore come from the knowledge graph and what the ontology says it implies. In the SPARQL tab, a query says how many of its rows exist only through reasoning, and the wiki's infoboxes mark inferred facts.
Version 1.3 of the ontology added components: a large work can be described part by part, each part with its own source file and the techniques it implements. This site is the first work described that way. Versions 1.5 and 1.6 added time, aligned with OWL-Time: years, and months of work with their commits and active days, so the graph knows not only that a work exists but when it was worked on. Version 1.12 added property chains: the skills a role or a year drew on are inferred from the work done in it, never written down by hand, so "what did he do at NARIT" and "what did he do in 2025" name the skills behind the work. Version 1.13 added explicit live destinations and single-valued live/source resource roles while preserving general related URLs. The current ontology, version 1.14.0, also provides cj:implementationDigest for generated provenance of local components' declared source files. A local wiki about resource is supplied by the catalog rather than requiring individual URL triples.
The parts of the site
| Part | Source | What it does |
|---|---|---|
| Question engine | src/engine.js | Entity linking, intents, rank fusion, spelling |
| SPARQL engine | src/kg.js | SPARQL over the graph, in the browser |
| Turtle parser | src/turtle.js | Turtle files to triples |
| Reasoner | src/reason.js | Facts the ontology implies |
| Wiki full-text search | src/search.js | BM25 over wiki passages |
| Timeline view | src/timeline.js | Roles and work over time |
| Graph view | src/graph.js | The graph and the ontology as a network |
| Time data | scripts/build-time-ttl.mjs | Years and months of work, for questions about when |
| Page builder | scripts/build-pages.mjs | Prerendered pages, JSON-LD and the sitemap |
| Fact check | scripts/factcheck.mjs | Wiki facts against their articles |
| CV builder | scripts/build-cv.mjs | The CV page and its PDF |
| Question log | api/log.js | Questions and votes, for finding bad answers |
| Contact form | api/mail.js | Messages sent from the Mail page |
| Easter eggs | src/eggs.js | A few queries that do something else |
| Logo and doodles | src/brand.js | The cj mark, and its costumes on special days |
| Offline support | sw.js | Keeps the site answering without a connection |
| Accessibility audit | tests/audit.mjs | Names, contrast, tap targets and speed, checked weekly |
The wiki, the timeline and the graph
Every entity in the graph has a page in this wiki. Some have a written article like this one; the rest are generated from the graph, with an infobox, the works linked to them and, for general things, a summary from Wikipedia. The page builder also prerenders every page as plain HTML with JSON-LD structured data and lists them in an XML sitemap, so search engines can read the wiki without running any JavaScript.
The timeline draws every role and every piece of work on one axis, each work as a line from its first commit to its last. Clicking a year, a role or a theme narrows it down and asks the matching question.
The graph view shows the same graph as a network. It opens on an overview of his key work, the themes and the skills they share, and opening anything brings its neighbours in; the places come from a force-directed layout settled once at deploy time. A second view draws the ontology itself: its classes, how they nest and the properties between them.
Stack
There is no framework: the page is plain JavaScript, HTML and CSS, hosted on Vercel. A few small Node.js functions sit behind it. The question log keeps typed questions in Postgres on Neon, Redis caches answers and enforces rate limits, and the contact form forwards messages through Resend. On every push, GitHub Actions validate the graph, check the pages in a real browser with Playwright, and print the CV to PDF; every day they refresh the site's own dates and months of work, and every week the accessibility audit runs. Both scheduled graph refreshes also rebuild and commit the wiki catalog after time data, keeping its entity snapshot current. A service worker caches the complete local module dependencies, graph and search index for offline lookup; optional model augmentation and external sites still require a connection.
Privacy
Typed questions are logged as text, with the kind of question and whether it was answered, to find questions the site gets wrong. No IP address is stored with them, and there are no cookies, ads or trackers. Recent searches stay in your own browser.
Related
KiWiS is the readable knowledge layer of the same research network, and the knowledge-graph explorer is its workspace for large graphs. This site is the front door for finding those entities, choosing their resources and asking about the work behind them.
The logo is the letters cj, for the cj: vocabulary the whole graph is written in, drawn as a tiny graph: the dot of the j is a node, linked to the c. On some days it dresses up. There are a few easter eggs too; try "askew" or "donut".