Manufacturing Engineer & Data Analyst with 18 years of experience, specializing in data analysis, open source contribution, and business automation.
Jump to — Robotics · Baseball websites · Realtime open data · Baseball analytics · Open source · Competitions · Dashboards and mobile · PyPI · Learning projects · Tech stack · Career · Patents · Contact
stackchan-lab — M5 Stack-chan Development Log (Active)
Official M5Stack Stack-chan (M5STACK-K151) moved off its stock cloud assistant onto a self-hosted stack on a Raspberry Pi 5 - 19 server-side tools · 11 device tools over MCP · sings 16 cheer songs · speaks while the model is still writing · stock firmware, unmodified
How the voice loop runs
| Stage | |
|---|---|
| Speech in | sherpa-onnx / ReazonSpeech, on the Pi |
| Reply | hosted 120B model, free tier |
| Speech out | Open JTalk, on the Pi (0.27s per sentence), shaped for a speaker that cannot reproduce bass |
| Tools | weather, FX, indices, crypto, NHK headlines, JMA quake / warning / typhoon, heat index, train delays, on-this-day, moon and sun, fuel surcharge, travel advisories, baseball scores and standings, roster notices, cheer-song lyrics, singing a cheer song |
| Device tools | camera, head angles, LED, volume, screen, battery - called through the same function-call array |
| Interrupting | the device sends no mic while it is playing, so the server stops the audio and listens at a silent point |
| Latency | the reply is spoken sentence by sentence as it streams, and only the utterance that just ended is sent to the recogniser |
What went wrong, and what it turned out to be
| Symptom | Cause |
|---|---|
Pairing failed as No devices found |
Factory firmware nine releases behind. OTA needs Wi-Fi, Wi-Fi setup needs pairing - USB was the only way in |
| Device kept talking to the stock server | A hand-appended NVS entry padded its key with 0xFF instead of 0x00: valid CRC, invisible to my own parser, permanently missed by ESP-IDF |
| OOM-killed at 7GB RSS, twice | A VAD that starts counting at speech never fires on an always-streaming mic |
| Speech played in slow motion | Not length - the same 30 morae read fine as nonsense but break in a real sentence, and one comma puts it right. The server times each synthesis and re-splits what came out slow |
| The rhythm would not come back, whatever I changed | The wall was the ruler. Against a real recording, comparing sound to sound has a floor of 142-680ms: singing at the onsets of the recording itself, which cannot be wrong as rhythm, still reads that, and every difference I had been reading between methods sat inside it. Measured by times against times, with a random control beside it, the notes now land 20-60ms from the onsets against 55-105ms for random - and it sings |
| Conversation sounded quieter than the singing | Not level - band. The singing voice puts over 90% of its energy above 500Hz; the speaking voice puts 73-84% below it, where a speaker this small reproduces nothing. Matching the level in the band that is actually audible fixed what matching the overall level could not |
More of the same, with the measurements behind each, is in the server notes.
Write-up, measurements and tests: stackchan-lab
M5Stack CoreS3 (ESP32-S3) / Raspberry Pi 5 / Python (aiohttp, WebSocket) / sherpa-onnx + ReazonSpeech / Open JTalk / MCP / Opus
rpi5-infra 🔒 (private, config record)
Configuration record for the Raspberry Pi 5 that hosts the robot's server, kept so the box can be rebuilt after an SD failure and so a change like opening a port leaves a trace.
What it records, and what it deliberately leaves out
| Recorded | firewall rules, systemd units, cron entries, listening ports, an inventory of what is actually running |
| Left out | secrets - unit files reference their EnvironmentFile without containing values, and credential files are excluded |
Raspberry Pi OS / systemd / ufw / cron / Tailscale
Minami Baseball OB — Alumni Association Site (In Production)
Full-stack web app for a high school baseball alumni association — 11 active users · 44 pages · 23 DB tables · 19 e2e tests · ¥0/mo running cost (157 files, ~18200 LOC). Technical Documentation
| PC (Light) | Game Results |
![]() |
![]() |
5-tier RBAC (Middleware + RLS), automated member pipeline (Form → GAS → Actions → Supabase), 686 match records (1955–present)
Architecture & features
- 5-tier RBAC (guest → admin): Next.js Middleware + Supabase RLS — authorization at route, row, and component level
- Automated member pipeline: Google Form → Apps Script → GitHub Actions auto-PR → Supabase role sync. Personal names never touch Git
- Custom CMS: 9 editor pages + 5 inline edit, soft delete (7-day trash + auto-purge), change history, audit logs
- 686 match records (1955–present): cross-source verification, generation-based grouping, per-game photo management
- UX: Unsaved warning, Web Share + LINE fallback, Calendar registration, ripple feedback, Suspense skeleton UI, weather forecast (Open-Meteo, 10 venues), automated game detection (2 sources → auto-PR)
- Security: RLS on all 23 tables (17 main + 6 history),
server-onlyadmin, CODEOWNERS, branch protection, secret scanning, cookie consent, 60-min session timeout - Silent-fail monitoring — built after a 1-month silent outage (a Form trigger silently lost its OAuth grant):
- Hourly health-check probes the full member-request + feedback pipeline (Vercel proxy / dispatch chain / GAS time trigger / gas-issue-form secret match / role-sync recency)
- Workflow-run failure + sync-roles liveness (cron-stall) detection auto-opens a tracking GitHub issue and auto-closes it on recovery
- Dual-channel alerts: GitHub Actions email + GAS Gmail
Next.js 15 / TypeScript 5.8 / Tailwind CSS 4 / Supabase (PostgreSQL + Auth + Storage) / Vercel / GitHub Actions / Google Apps Script / GA4
Yokohama Funnies — Amateur Baseball Team Site (In Production)
Companion site for an amateur baseball team, forked from Minami Baseball OB — 23-player roster · 48 pages · 31 DB tables · 18 e2e tests · ¥0/mo running cost (165 files, ~23100 LOC). Technical Documentation
5-tier RBAC (Middleware + RLS), PR-based member approval (Form → GAS → Actions auto-PR → merge → role sync), custom amateur-baseball stats schema (per-game batting / pitching / attendance) with manual-input + spreadsheet-migration ingestion
Architecture & features
- 5-tier RBAC (guest → admin): Next.js Middleware + Supabase RLS — authorization at route, row, and component level (Google OAuth)
- PR-based member approval (same topology as Minami): Google Form → Apps Script → Vercel proxy → GitHub App auto-creates an approval PR adding a per-member role file (
config/members/<uid>.yml); merging triggers a polling role-sync to Supabase + an approval email to the member — approve by merge. Personal data stays minimal in Git - Amateur-baseball stats schema:
players(jersey / bats / throws / is_guest / photo / comment), per-gamegame_player_batting(14 cols) +game_player_pitching,attendances(○/△/×); aggregated views + client-side season filter compute 打率 / 出塁率 / 長打率 / OPS / ERA / WHIP / K9 - Stat ingestion: spreadsheet migration + editor manual-input UI (
/edit/game-stats, scorebook image side-by-side + per-player grid); editors upload scorebook images straight from the result page - Custom CMS / UX: dedicated + inline editor pages, soft delete (7-day trash + auto-purge), change history, audit logs, public No. 06 ROSTER section (photo + jersey + role + comment) via
players_publicview, Open-Meteo weather forecast with WBGT heat-stress display - Security: Supabase RLS on all tables, anon-readable roster view with sensitive columns filtered, server-only admin, gitleaks secret scanning, notifications isolated on a separate public Actions repo
- Silent-fail monitoring:
- Hourly health-check probes every notification path (Vercel proxy / dispatch ack / GAS heartbeat / feedback webhook secret)
- Workflow-run failure + sync-roles liveness detection auto-opens/closes a GitHub issue, with email alerts on any silent failure
Next.js 15 / TypeScript 5.8 / Tailwind CSS 4 / Supabase / Vercel / GitHub Actions / Google Apps Script
| Japan Geohazard Monitor | Persian Gulf Ship Tracker |
![]() |
|
| 31 geophysical data sources → ML earthquake prediction (walk-forward pooled AUC 0.907 over 37 windows; +0.005 per window over a climatology fitted on the same rows) + real-time monitoring dashboard | AIS vessel tracking across the Persian Gulf & Gulf of Oman with land mask filtering 🛑 Stopped — RPi5 SSD failure (2026-05-16). |
Real-time API / WebSocket → SQLite → FastAPI + Leaflet.js (dark theme) — All projects
Japan Geohazard Monitor — Earthquake prediction research
Data sources, evaluation and the Kumamoto InSAR result
- 85 features from 25+ sources — USGS, NASA Earthdata, INTERMAGNET, NMDB, NOAA, IOC
- Walk-forward evaluation — a HistGBT ensemble on a 1° grid, scored on 3,004,835 rows across 37 windows from 1989 to 2026: pooled AUC 0.907, Brier skill +0.080.
- What that number is and is not — most of it is geography. A climatology fitted on the same rows reaches 0.902 on its own, so the part that is forecast rather than base rate is +0.005 per window, positive in 92% of windows. Reading the figure without its climatology overstates it.
- How rounds are judged — a round that returns a verdict is pre-registered before it runs, its scripts and its verifier are frozen by checksum before the first window is walked, and it is read against permutation or twin floors rather than against zero. Exploratory sizings, which decide whether a round is worth running at all, are labelled as sizings and never reported as verdicts. Null results are logged in the same place as the positive ones (research log)
- Current axis: the isolated mainshock — the pooled figure is carried by aftershock sequences, so since 2026-09 the work targets shocks that are not aftershocks of anything larger, in a causally-selected global arena of 2,280 cells over 36 windows, on a bare climatology rather than the shipped forecast
| Where the 0.907 comes from | Arm over its climatology, per window |
|---|---|
| aftershock-driven positives (39% of them) | +0.018 |
| isolated mainshocks (61%) | +0.007 |
| the strict 11% — no M≥4 within 50 km in the prior year | +0.010, and it fails its own interval |
| Rounds on that axis | Per window | |
|---|---|---|
| Aim the readout at large mainshocks (M6.0) | +0.0027 | floored |
| Replace the fitted readout with a per-cell rate counted from past events alone — no model, no feature columns | +0.0086 | floored; beats the fitted version by +0.0059 |
| Smooth that rate toward its neighbours | +0.0029 | floored on the retake. The first attempt passed on the run and failed its own frozen verifier: the contract defined the kernel's separation only as a great-circle distance, and the one formula it did name sat inside a gate; a regular lattice puts hundreds of cell pairs within a billionth of a degree of its hard cutoff |
| Bend the kernel into an ellipse along the local axis of past events | it loses | the control turned across the axis gains instead |
| A width that varies per cell, with no direction in it | +0.00045 | null when the strength is chosen causally; +0.00045 is a strength the contract disclosed up front as picked after seeing it win, and it comes second of ten against a floor that shuffles widths only among cells with the same neighbour count, so the two explanations stay undecided |
| Build the rival arm instead of a third floor (sizing: no contract, no floor) | +0.00047 | a width set from the neighbour count alone, carrying no seismic quantity, cannot be told apart — a statement about the smoother at the edge of the studied region, not about the earth |
| Measure what an edge cell's kernel actually does (sizing; its control worlds are the previous round's own) | +0.00127 | only on the quarter of negatives sharing a window with a positive; it fails on the other three quarters. The gain is a reordering of active cells, not a better rate estimate — the frozen prediction said the opposite, and correction is withdrawn |
- What none of that establishes — each verdict is rank one against five or nine permutation worlds, which is not a p-value, and none is an independent estimate of its own size: sizing saw the numbers before the contracts were frozen, and the third row's shape was chosen after a different one failed. The last two rows are sizings, with no contract and no floor, whose rival arms were designed after seeing the round they rival. Event-by-event discrimination has not been demonstrated, and magnitudes are not compared across catalogues, so none of it is a statement about Japan
- Open data & automation — features published as a public Hugging Face dataset, weekly CI pipeline on GitHub Actions
- Co-seismic InSAR — 2026 Kumamoto M7.1 measured from open Sentinel-1 on ASF HyP3: line-of-sight displacement −21.7 to +15.0 cm and a coherence-change damage proxy (method, figures and caveats)
Japan Wildlife Sightings — Bear and wildlife sighting open data, normalized · map
Why it exists, what is collected, and what is withheld
- The data is public but incompatible — prefectures publish bear, boar and deer sightings as CKAN CSV, ArcGIS Survey123, Google My Maps KML, Excel or PDF. The Ministry of the Environment publishes monthly totals as PDF only, so no nationwide point dataset exists. The aggregators that do exist are closed.
- 27 sources, 79,394 records in one schema (75,743 with coordinates), rebuilt daily on GitHub Actions and checked by a validator that counts coordinates, dates and duplicate ids.
- Only what the terms allow is published — 40,241 records from sources that state CC BY or PDL 1.0 (Akita, Kyoto, Ishikawa, Kanazawa, Yamaguchi, Sapporo, Muroran, Ishikari, Kamisunagawa). Every other source ships as a fetcher, not as data, with the licence wording quoted in docs/licenses.md.
- Finding the data is most of the work — a prefecture page often links only a PDF while a public ArcGIS layer sits behind its map (Toyama 4,614 records, Fukushima 4,491). Most PDF-only prefectures publish monthly totals rather than per-incident rows; the two that don't are parsed back, one by layout and one by glyph coordinates.
- A map, not just a file — MapLibre GL JS over GSI tiles, GSI aerial photography and NASA GIBS VIIRS imagery from the previous day. Library and glyphs are vendored, so the page depends on no external CDN.
| Project | Description | Demo |
|---|---|---|
| NPB Season Prediction | Bayesian ensemble (Marcel 35% + Stan/Ridge 40% + ML 25%) + Monte Carlo team simulation + 24 foreign player individual projections | Live |
| NPB 2021 Backtest | Could Bayesian model predict Yakult & Orix last→champion? 25 foreign players with FanGraphs data | Analysis |
| MLB Win Probability Engine | 3-engine ensemble WP (Normal + Empirical + LightGBM) + Gemini AI commentary | Live |
| Baseball MLOps Pipeline | Statcast MLOps: 5-model ensemble — weekly auto-retrain paused (BigQuery retired 2026-04, data layer being rebuilt on Hugging Face) | Live |
| MLB Data Pipeline | Shared data platform — FanGraphs + Savant + Statcast published as a public Hugging Face dataset, weekly auto-refresh via GitHub Actions | HF Dataset |
Prediction accuracy & details
| System | Key Metric | Articles |
|---|---|---|
| NPB 2026 | 8-yr backtest wOBA MAE .0498, 97% prob. of beating Marcel. 10K Monte Carlo sims | JP / EN |
| NPB 2021 Backtest | MAE 10.7W — Yakult & Orix last→champion driven by JP player breakouts, not foreign players | Repo |
| MLB WP Engine | 3-engine ensemble, 367K+ play states (2015–2024), inverse-Brier weighted + Isotonic calibration | Live |
| Baseball MLOps | Batter wOBA MAE .0287 (Marcel: .0326) / Pitcher xFIP MAE 0.483 (Marcel: 0.558) | Live |
Baseball Skeleton Analysis — 3D skeleton visualization from Driveline OpenBiomechanics C3D data
| Pitching Skeleton (3D C3D) | Hitting Skeleton (3D C3D) |
![]() |
![]() |
Trunk rotation range vs pitch speed: r=0.425 (strongest). Contributed bug fix PR #384 to ezc3d. Article (JP) / Article (EN)
Handwritten Scorebook OCR 🔒 (private R&D, active)
Reads handwritten Japanese paper scorebooks (紙スコアブック) from photos into structured at-bat data — no paid API, no cloud OCR · deterministic OpenCV on a Raspberry Pi 5 · a base-running constraint solver decides what the marks mean · graded on 31 hand-transcribed sheets
Where it stands
| Configuration | Score |
|---|---|
| Grid facts handed over (shipped default) | 331 / 356 = 93% |
| No grid fact handed over at all | 328 / 356 = 92% |
| ...and every recognition in-house as well | 252 / 356 = 71% shipped; 291 = 82% under a price order chosen after seeing the result |
| Hardest mark class: template matching alone → fused with the solver | 76% → 93% |
| Consecutive held-out sheets — each new game is graded before it joins the pool | 29 |
| Real output | my team's 2026 season batting stats are compiled from this ground truth |
What the last rounds changed
| Change | Result |
|---|---|
| Which column is which inning: cut from the ledger, read off the paper | A gate demanding each inning read exactly {I, II, III} left the truth reachable on 3 sheets of 31; pricing it instead reaches all 31 |
| The last hard gate — an inning holds at most three batter outs — allowed to be outbid | Worth 36 corners where the out/reach call is made in-house, under a price order arrived at after the fact. With every recognition in-house as well, the gap to reading the ruling lines back falls from 43 corners to 4 |
| Adversarial review of the diagnostic behind that claim | It had been run without the flag it was describing, so the number meant something else. Re-measuring properly is what produced the 36 above |
| Nine ways to stop spurious marks pinning the wrong batter | All null, against a measured ceiling of +14 corners |
Private repo (the method is the product) — public technical write-up: baseball-scorebook-ocr-docs (JP)
6 analyses covering Japanese MLB pitchers and Ohtani batting data.All analyses (6)
| Analysis | Key Finding | Article |
|---|---|---|
| Kikuchi Slider Revolution (2019-2025) | SL 17%→37% after Astros trade | Zenn / DEV.to / Kaggle |
| Senga Ghost Fork (2023-2025) | FO whiff rate 58%→39%, decline pre-injury | Zenn / DEV.to / Kaggle |
| Imanaga 2nd Year (2024-2025) | 3-pitch concentration (97%), 1st TTO xwOBA .505 | Zenn / DEV.to / Kaggle |
| Darvish Evolution (2021-2025) | SL/ST halved, CU became putaway pitch | Zenn / DEV.to / Kaggle |
| Ohtani Spray Chart | spraychart() one-liner vs matplotlib manual | Zenn |
| Ohtani Heatmap | Stadium drawing + hit density heatmap | Zenn |
(129 PRs / 80 Merged) across 49 repositories. See [oss-contributions](https://github.com/yasumorishima/oss-contributions) for full details.
PR highlights (click to expand)
| Repository | PR | Description |
|---|---|---|
| dfinity/icp-js-core | #1270 | Improve Candid decode error messages |
| line/line-bot-mcp-server | #369 | Add get_follower_ids tool |
| pyomeca/ezc3d | #384 | Fix __eq__ early return bug |
| codeforjapan/mapprint | #556 | Share buttons on the disaster print map |
| codeforjapan/mapprint | #564 | Deterministic list order on the printable map |
| codeforjapan/mapprint | #563 | 2026 Kumamoto earthquake paper map |
| codeforjapan/BirdXplorer | #281 | Statement timeouts for the Community Notes API |
| hotosm/openaerialmap | #289 | Stop the STAC ingester dropping the wrong record when an entry fails |
| apache/fineract-backoffice-ui | #321 | Translate the accounting screen titles and tooltips |
| daisy/MathCAT | #665 | Fix chemistry assertions that could never fail |
| daisy/MathCAT | #720-756 | Japanese speech rules, 19 merged PRs: fractions in Japanese word order, exponents, negative numbers, roots, geometry terms, brackets, large operators, intervals, mathematical vocabulary, elementary functions, accents, symbol readings, function application, nPk permutations, menclose marks, the navigation command prefixes, the rule vocabulary and the shared-rule vocabulary |
| daisy/MathCAT | #746 | Fix the Japanese navigation announcements a blind reader hears on every move, including four that stated the opposite of the truth at the edge of a table |
| PHPOffice/PHPPresentation | #897 | Fix PHP 8.4/8.5 static analysis by fixing 144 findings instead of ignoring them |
| project-inclusive/OpenFisca-Japan | #479 | Add the vocational training benefit for single-parent families to Japan's welfare rules engine |
| project-inclusive/OpenFisca-Japan | #480 | Add the housing security benefit to Japan's welfare rules engine |
| project-inclusive/OpenFisca-Japan | #481 | Add the welfare loan fund for single-parent families and widows to Japan's welfare rules engine |
| project-inclusive/OpenFisca-Japan | #482 | Add the school-cost assistance eligibility check to Japan's welfare rules engine |
| project-inclusive/OpenFisca-Japan | #483 | Add the higher-education tuition and entrance-fee reduction to Japan's welfare rules engine |
| project-inclusive/OpenFisca-Japan | #484 | Add the jobseeker support benefit paid during free vocational training to Japan's welfare rules engine |
| optuna/optuna | — | Hyperparameter optimization framework |
| pandas-dev/pandas | — | Data analysis library |
| jldbc/pybaseball | #498-504 | Bug fixes & documentation |
team-mirai — Civic Tech OSS (26 PRs (14 Merged / 4 Open / 8 Closed))
Civic tech projects for political transparency & citizen participation in Japan. Next.js / TypeScript / Supabase / Vitest.
| Repository | Highlights |
|---|---|
| action-board | 48 unit tests, RPC tests, breadcrumb nav, cache fix + 5 more |
| mirai-gikai | Supabase CLI v2.106 seed permission fix, Safari/iOS ruby spacing fix |
| fact-checker | X API investigation + 5 PRs |
Notebooks Expert | 🥉 15 Bronze Notebook Medals
Active:
- SIGNATE NEDO Challenge — Baggage-Loading Optimization — 3D bin packing for airline ULD containers, hybrid offline+online packing agent (¥15M prize pool, Jul–Oct 2026) — public score 43.44 as of 2026-09-06, scored on fill rate, centre of gravity, stability under shaking and placement of priority/soft cargo
- 5th Air Combat AI Challenge (SIGNATE, run by Japan's Acquisition, Technology & Logistics Agency) — behaviour-decision agents for a 4-fighter plus 1 escorted-aircraft engagement in the organiser's simulator · Glicko-2 rating over agent-vs-agent matches · entries stay private until the contest closes (¥1.92M prize pool, to 2026-12-04)
- Kaggriculture — two-player farm-economy simulation, scored by ladder rating rather than by money ($50K prize pool, to 2026-09-30). Agent and its measurement harness in
kaggle-competitions/kaggriculture
Finished 2026: ROGII Wellbore Geology ($50K wellbore TVT regression, closed 2026-08-05 — public LB 7.311, final public rank 2545/6125) · Playground Series S6E6 - Stellar Classification (macro-F1, private LB 0.95939) · NIR Moisture Prediction (SIGNATE, wood spectroscopy) · Stanford RNA 3D Folding 2 · BirdCLEF+ 2026
Bronze Medal Notebooks (15)
| Notebook | Topic |
|---|---|
| savant-extras Defense & Pitching Quality | Defense metrics & pitching quality (savant-extras) |
| MLB Statcast Spray Charts for WBC 2026 | WBC 2026 spray + pitch zone charts (baseball-field-viz) |
| March Machine Learning Mania 2026 | NCAA tournament prediction (LightGBM) |
| NFL Geometric Rules Baseline | Physics-based rules, No ML, RMSE 2.921 |
| CAFA 6 Baseline | Protein function prediction (PyTorch MLP) |
| Dataset | Description |
|---|---|
| 🥈 MLB Bat Tracking Leaderboard (2024-2025) | 452 batters, 19 swing metrics |
| 🥈 WBC 2026 Scouting | 306 players, 20 countries |
Other datasets (6)
| Dataset | Description |
|---|---|
| Baseball Savant Leaderboards (2024-2025) | 15 leaderboards, 2 seasons combined |
| Japanese MLB Players Statcast (2015-2025) | 34 Japanese MLB players, 174k pitches+hits |
| MLB Pitcher Arsenal Evolution (2020-2025) | 4,253 pitcher-seasons, 111 metrics |
| MLB Statcast + Bat Tracking (2024-2025) | Combined Statcast + bat tracking data |
| XC BirdCLEF 2026 Target Recordings (URLs) | Xeno-canto source URLs for the 2026 target species |
| BEATs iter3+ AS2M Pretrained | Audio-tagging checkpoint mirrored for offline notebooks |
DrivenData Competitions — Automated pipeline: GitHub Actions + GPU training + GPU→CPU fallback. Most recently competed in On Top of Pasketti (Children's ASR, $120K prize, Wav2Vec2 CTC; submission deadline 2026-04-06).
| App | Description | Link |
|---|---|---|
| MLB Bat Tracking Dashboard | Leaderboard, Player Comparison, Team Lineup Builder. Powered by savant-extras | Live |
| WBC 2026 Scouting Dashboard | 30 Statcast apps across 19 countries. Zone heatmaps, spray charts, pitch movement | Live |
| Daily Diary | Flutter mobile app, 10 languages, offline-first, biometric app lock, daily reminder, Android Auto Backup, AdMob · screen-reader support (every tappable control labelled for TalkBack, mood selection state, live-region save celebration; CI fails the build if any control ships unnamed, audits the real accessibility tree on an emulator, and measures the spoken audio of every label) · links to Sansuu/Shogi/Sora (ja only) | Google Play |
| Fire Tablet Google Play Helper | Detects Fire OS from the browser UA, then lists the four required APKs in install order with step gating and saved progress | Live |
WBC 2026 Scouting Dashboard details (30 apps)
30 Statcast scouting apps across 19 countries (batters + pitchers). Zone heatmaps, spray charts, pitch movement, LHP/RHP splits. Auto-fetched via GitHub Actions. → USA Batters / Japan Pitchers / All 30 apps
icrc167-android — Internet Identity login for native Android (Active)
The relying-party side of ICRC-167, so an Android app can sign a user in with Internet Identity and then call canisters directly — no bridge server and no backend of its own. An iOS implementation exists; the Android counterpart did not.
Seven things that were measured rather than assumed
| Question | What the measurement said |
|---|---|
| Does the URL fragment survive an App Link hand-off? | It does — 379 bytes, matching SHA-256, over both delivery paths. The transport returns the delegation there and nowhere else, while intent-filter matching ignores the fragment entirely, so it was worth checking rather than assuming. The same run caught Uri.getFragment() percent-decoding the payload and inventing a parameter that was never sent |
| Does the device test prove anything? | Not at first. The principal is derived from the root key in the response, so a passing positive case would have passed just as well with signature checking removed. The negative cases — an answer carrying somebody else's state, a signature that does not verify — are the test; the positive one only shows the parts still fit together |
| Is the hash right? | The same function produced the bytes that get signed and the bytes that get verified, so it agreed with itself and with nothing else. It is now pinned to the worked request-id example published in the interface specification |
| Do the negative tests reach the check they are named for? | The pairing equation did not. Replacing it with return true left every test green, because each negative case altered a byte of a compressed point and so died at the decoder or the subgroup check first. It is pinned now by cases where only the equation can decide — with the mutation pushed to CI both before and after, rather than reasoned about |
| Can the round trip be tested before Internet Identity is in the picture? | Yes — any Ed25519 key may delegate, so a chain signed here comes back from mainnet as the principal that delegated, and the same chain signed by the wrong key is refused |
| Do the published test vectors settle the rules? | Not all of them. A delegation must state its subnet's type; no canister signature in the public record carries it and a certificate fetched from id.ai does — the vectors are simply older than the rule |
| Does verifying the certificate bind the answer to the canister? | Not on its own. The canister-range check runs only when the certificate is delegated; an undelegated one verifies to the root key without ever looking at the canister, and the root state tree holds the node keys of every subnet. One genuine certificate would otherwise let any node answer for anything, so the binding is made explicitly |
A chain can be checked from outside now, not only against itself: the library makes the call, a canister answers with the principal it sees, and the node signature on that answer is verified to the network root key. What is left is a real passkey on a device.
Kotlin / Android (Custom Tabs, App Links, Keystore) / BLS12-381 · Ed25519 · ECDSA P-256 · SHA-256 / CBOR / GitHub Actions (JVM tests + emulator)
6 packages (click to expand)
| Package | Description |
|---|---|
| savant-extras | 17 Baseball Savant leaderboards + date range support. Complements pybaseball |
| baseball-field-viz | Statcast coordinate transform + field drawing + spray charts + pitch zone charts |
| kaggle-notebook-deploy | Deploy Kaggle Notebooks via git push + GitHub Actions |
| kaggle-wandb-sync | Sync W&B offline runs from Kaggle to W&B cloud |
| signate-deploy | SIGNATE competition workflow via GitHub Actions |
| signate-wandb-sync | Record SIGNATE scores to W&B runs |
| Project | Description |
|---|---|
| Sansuu, Shogi & Sora | Four modes on the Internet Computer: arithmetic (36 topics) · shogi · sora, a planetarium drawing the real sky for any place and time · play, six toddler games — moles, balloons, spoken picture words, fish, finger drawing and sound bars — none of which asks the child to read a letter. Usable without sight — the sky is spoken (direction in degrees, altitude, nearest object) and every game answers the screen reader and the keyboard. English/Japanese, offline, records on-device — Live |
| OpenClaw Twitter Bot | Raspberry Pi 5 + OpenClaw + Gemini API auto-tweet bot (stopped) — Article (JP) |
| alexa-rpi5 🔒 | Raspberry Pi 5 to Fire TV Cube control hub for a house with no Echo speaker: cube wrapper, watchers and integrations (details in the repo README) |
Past Projects
| Project | Description |
|---|---|
| GAS Calendar Tool | Batch calendar event registration with senior-friendly mobile UI |
| Dune Analytics | On-chain data analysis — JPYC Stablecoin Dashboard |
| selenium-to-playwright 🔒 | Playwright browser automation: 20+ scripts + night batch runner with auto GitHub Issues |
| Archived Projects | Selenium automation, business workflow tools, etc. |
| Category | Technologies |
|---|---|
| Data Analysis & ML | Python, pandas, scikit-learn, LightGBM, XGBoost, CatBoost, PyTorch, matplotlib, seaborn, DuckDB, W&B |
| Data Platform | Hugging Face Datasets (MLB / NPB / geohazard — public, auto-refreshed via GitHub Actions), SQLite, |
| Data Sources | Baseball Savant (Statcast), pybaseball, USGS, NASA Earthdata, AIS |
| Web & Dashboards | Streamlit, Next.js, TypeScript, Supabase, Vercel, shadcn/ui |
| Mobile App | Flutter, Dart, Hive, Google AdMob |
| Automation & DevOps | GitHub Actions, Google Apps Script, VBA, Power Query |
| Tools | Claude Code, Kaggle, Google Colab, Excel, Looker Studio |
| Manufacturing | Statistical Quality Control, Process Engineering |
- 2024 - Present: Quality Management @ a semiconductor distributor
- 2008 - 2024: Semiconductor Manufacturing Process Engineer
- 2008 - 2014: Toppan Printing
- 2014 - 2017: Toshiba → Toshiba Memory (now Kioxia)
Stencil mask and manufacturing method thereof
- Patent No: 6307851
- Role: Inventor
- Link: Google Patents (JP6307851B2)
- Site: https://yasumorishima.github.io — tools and blog hosted on this domain
- Blog: DEV.to (EN) / Zenn (JP) / Quarto Blog (EN)
- Kaggle: https://www.kaggle.com/yasunorim
- Wantedly: https://www.wantedly.com/id/yasunori_morishima_b
- LinkedIn: https://www.linkedin.com/in/morishima-yasunori-b70229241








