SOURCE / PINNED RELEASE
Made of little things.
Napplet Machines V8
- Release
- b3f614e739f0…
- Author-recorded commit
- 534f19acb4ba…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-b5572362d4a
Archive hash verified: 0f7feb97e2c3d336…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import { mkdir } from 'node:fs/promises';
export default async ({ players, check }) => {
const { page, frame } = players[0],
element = await frame.frameElement();
await page.setViewportSize({ width: 1200, height: 750 });
await element.evaluate((el) =>
Object.assign(el.style, {
position: 'fixed',
top: 0,
left: 0,
width: '1200px',
height: '750px',
minHeight: 0,
border: 0,
zIndex: 9999,
}),
);
await frame.waitForFunction(() => innerWidth === 1200 && innerHeight === 750);
await frame.evaluate(() => document.fonts.ready);
await mkdir('.napplet-space/promotion', { recursive: true });
await element.screenshot({
path: '.napplet-space/promotion/island-overview.png',
});
const native = await frame.evaluate(() => {
try {
return (
typeof navigator.getGamepads === 'function' &&
Array.isArray(navigator.getGamepads())
);
} catch {
return false;
}
});
check('native Gamepad API is callable in the opaque hosted frame', native);
await frame.locator('#scene').focus();
await frame.evaluate(() => {
window.__originalGamepads = navigator.getGamepads.bind(navigator);
window.__pads = [];
window.__pad = (index, mapping = 'standard') => ({
index,
id: `Synthetic pad ${index}`,
mapping,
connected: true,
axes: [0, 0],
buttons: Array.from({ length: 17 }, () => ({
value: 0,
pressed: false,
touched: false,
})),
});
window.__pads[3] = window.__pad(3);
Object.defineProperty(navigator, 'getGamepads', {
configurable: true,
value: () => window.__pads,
});
});
const button = async (index, value, slot = 3) => {
await frame.evaluate(
({ index, value, slot }) => {
window.__pads[slot].buttons[index].value = value;
},
{ index, value, slot },
);
await page.waitForTimeout(65);
};
const tap = async (index, slot = 3) => {
await button(index, 1, slot);
await button(index, 0, slot);
};
await page.waitForTimeout(100);
await tap(0);
check(
'explicit controller claim uses browser slot 3',
(await frame.locator('#controllerState').innerText()) === 'PAD 4',
);
check(
'claim does not accidentally start a race',
await frame.locator('#raceButton').isVisible(),
);
await tap(5);
check(
'controller chooses a car in the garage',
(await frame.locator('.car-name').innerText()) === 'Bumble',
);
await tap(4);
await tap(13);
check(
'controller chooses a course',
(await frame.locator('#trackSelect').inputValue()) === '1',
);
await tap(12);
await frame.evaluate(() => {
window.__pads[1] = window.__pad(1);
});
await page.waitForTimeout(80);
await tap(0, 1);
check(
'second controller cannot steal the active slot',
(await frame.locator('#controllerState').innerText()) === 'PAD 4',
);
await frame.locator('#gridSize').selectOption('2');
await frame.locator('#scene').focus();
await tap(0);
await frame.waitForFunction(
() => document.querySelector('#scene').dataset.countdown === '0',
);
check('controller starts a race', true);
await frame.evaluate(() => {
window.__pads[3].axes[0] = -0.5;
window.__pads[3].buttons[7].value = 0.65;
});
await frame.waitForFunction(() => {
const s = document.querySelector('#scene').dataset;
return (
Number(s.inputSteer) > 0.3 &&
Number(s.inputSteer) < 0.5 &&
Math.abs(Number(s.inputThrottle) - 0.65) < 0.01 &&
Number(s.localSpeed) > 1
);
});
check('analog stick and trigger drive the actual simulation', true);
await button(1, 1);
await frame.waitForFunction(
() => document.querySelector('#scene').dataset.inputBrake === 'true',
);
check('controller face button engages drift', true);
await button(1, 0);
await frame.evaluate(() => {
window.__pads[3].axes[0] = 0.08;
window.__pads[3].buttons[7].value = 0;
window.__pads[3].buttons[6].value = 0.45;
});
await frame.waitForFunction(() => {
const s = document.querySelector('#scene').dataset;
return (
Number(s.inputSteer) === 0 &&
Math.abs(Number(s.inputThrottle) + 0.45) < 0.01
);
});
check('stick dead zone and analog service braking work in the sandbox', true);
await button(9, 1);
await page.waitForTimeout(300);
check(
'held Menu pauses only once',
(await frame.locator('#pauseButton').innerText()) === 'Resume',
);
await button(9, 0);
await tap(9);
check(
'fresh Menu press resumes',
(await frame.locator('#pauseButton').innerText()) === 'Pause',
);
await frame.evaluate(() => {
window.__pads[3] = null;
});
await frame.waitForFunction(
() => document.querySelector('#pauseButton').textContent === 'Resume',
);
check(
'disconnect neutralizes input and pauses local play',
Number(
await frame.locator('#scene').getAttribute('data-input-throttle'),
) === 0,
);
await page.keyboard.press('Escape');
await page.keyboard.press('Escape');
await frame.waitForFunction(
() => document.querySelector('#countdown').textContent === 'PAUSED',
);
check(
'keyboard can take over pause after controller loss',
(await frame.locator('#pauseButton').innerText()) === 'Resume',
);
await frame.evaluate(() => {
window.__pads[3] = window.__pad(3);
window.__pads[3].buttons[0].value = 1;
});
await page.waitForTimeout(100);
check(
'reconnected held button cannot claim or resume',
(await frame.locator('#controllerState').innerText()) !== 'PAD 4' &&
(await frame.locator('#pauseButton').innerText()) === 'Resume',
);
await button(0, 0);
await tap(0);
await tap(9);
check(
'deliberate rejoin and resume work',
(await frame.locator('#controllerState').innerText()) === 'PAD 4' &&
(await frame.locator('#pauseButton').innerText()) === 'Pause',
);
await tap(9);
await tap(1);
await frame.waitForFunction(
() => document.querySelector('#scene').dataset.racing === 'false',
);
check('controller can exit a paused race to the garage', true);
await frame.evaluate(() => {
window.__pads = [];
window.__pads[2] = window.__pad(2, '');
});
await page.waitForTimeout(100);
await tap(0, 2);
check(
'unknown mappings keep keyboard and touch fallback',
(await frame.locator('#controllerState').innerText()) === 'UNMAPPED PAD' &&
(await frame.locator('#raceButton').isEnabled()),
);
await frame.evaluate(() =>
Object.defineProperty(navigator, 'getGamepads', {
configurable: true,
value: () => {
throw new DOMException('Not permitted', 'SecurityError');
},
}),
);
await page.waitForTimeout(100);
check(
'blocked gamepad API degrades without a crash',
(await frame.locator('#controllerState').innerText()) === 'PAD BLOCKED' &&
(await frame.locator('#raceButton').isEnabled()),
);
await frame.evaluate(() =>
Object.defineProperty(navigator, 'getGamepads', {
configurable: true,
value: window.__originalGamepads,
}),
);
};
