@johnmorrisdotca/kyogijo-stadiums 0.44.1 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/dist/areas-entry.d.ts +2 -0
- package/dist/areas-entry.js +2 -0
- package/dist/areas.d.ts +46 -0
- package/dist/areas.js +87 -0
- package/dist/cityctx.d.ts +3 -6
- package/dist/cityctx.data.d.ts +5 -8
- package/dist/cityctx.data.js +5 -7137
- package/dist/cityctx.js +3 -6
- package/dist/cityctx.seattle-center.data.d.ts +3 -0
- package/dist/cityctx.seattle-center.data.js +1883 -0
- package/dist/cityctx.seattle-city.data.d.ts +3 -0
- package/dist/cityctx.seattle-city.data.js +3778 -0
- package/dist/cityctx.seattle-sodo.data.d.ts +3 -0
- package/dist/cityctx.seattle-sodo.data.js +1419 -0
- package/dist/cityctx.vancouver-nature.data.d.ts +3 -0
- package/dist/cityctx.vancouver-nature.data.js +57 -0
- package/dist/context.d.ts +2 -0
- package/dist/context.js +20 -1
- package/dist/district.turn.js +61 -6
- package/dist/judging.mount.js +7 -0
- package/dist/outside.dom.d.ts +5 -0
- package/dist/outside.dom.js +13 -5
- package/dist/quality.d.ts +110 -0
- package/dist/quality.js +160 -0
- package/dist/turn-entry.d.ts +2 -0
- package/dist/turn-entry.js +1 -0
- package/dist/turn.camera.js +17 -7
- package/dist/turn.dom.d.ts +7 -0
- package/dist/turn.dom.js +198 -20
- package/dist/turn.kit.d.ts +5 -0
- package/dist/turn.markup.d.ts +16 -8
- package/dist/turn.markup.js +99 -20
- package/dist/turn.model.d.ts +13 -0
- package/dist/turn.style.js +6 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -1
package/dist/turn-entry.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export { buildTurn, floorOptions, openingView } from "./turn.model.ts";
|
|
|
4
4
|
export { turnDirection } from "./turn.camera.ts";
|
|
5
5
|
export type { TurnDirection } from "./turn.camera.ts";
|
|
6
6
|
export type { TurnModel, TurnSettings } from "./turn.model.ts";
|
|
7
|
+
export { GOVERNOR_TUNING, QUALITIES, QUALITY_TIERS, TIER_PROFILES, createGovernor, handheld, isQuality, qualityOf, rasterOf, tierOf } from "./quality.ts";
|
|
8
|
+
export type { Governor, GovernorTuning, Quality, QualityTier, TierProfile } from "./quality.ts";
|
|
7
9
|
export { layoutOf, planeMarkup, planeMatrix, turnMarkup, turnMarkupOf } from "./turn.markup.ts";
|
|
8
10
|
export type { Layout } from "./turn.markup.ts";
|
|
9
11
|
export { KYOGIJO_TURN_STYLE } from "./turn.style.ts";
|
package/dist/turn-entry.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export { mountKyogijoTurn, mountTurn, turnSupported } from "./turn.dom.js";
|
|
3
3
|
export { buildTurn, floorOptions, openingView } from "./turn.model.js";
|
|
4
4
|
export { turnDirection } from "./turn.camera.js";
|
|
5
|
+
export { GOVERNOR_TUNING, QUALITIES, QUALITY_TIERS, TIER_PROFILES, createGovernor, handheld, isQuality, qualityOf, rasterOf, tierOf } from "./quality.js";
|
|
5
6
|
export { layoutOf, planeMarkup, planeMatrix, turnMarkup, turnMarkupOf } from "./turn.markup.js";
|
|
6
7
|
export { KYOGIJO_TURN_STYLE } from "./turn.style.js";
|
|
7
8
|
export { CURLING_PRESETS, LONG_PRESETS, NET_PRESETS, PITCH_MAX, STEP, TURN_DEFAULT, TURN_PRESETS, TURN_PRESET_NAMES, ZOOM_MAX, ZOOM_MIN, cameraMatrix, clampView, depthOf, drag, eyeDistance, fit, matrix3d, multiply, nudge, presetOf, presetView, presetsFor, project, step } from "./turn.camera.js";
|
package/dist/turn.camera.js
CHANGED
|
@@ -181,11 +181,12 @@ export function fit(b, view, w, h, distance, pad = 0.03) {
|
|
|
181
181
|
}
|
|
182
182
|
/** Two matrices as one: `b` first, then `a`. */
|
|
183
183
|
export function multiply(a, b) {
|
|
184
|
-
const out = new Array(16)
|
|
185
|
-
for (let col = 0; col <
|
|
184
|
+
const out = new Array(16);
|
|
185
|
+
for (let col = 0; col < 16; col += 4) {
|
|
186
|
+
const [b0, b1, b2, b3] = [b[col], b[col + 1], b[col + 2], b[col + 3]];
|
|
186
187
|
for (let row = 0; row < 4; row += 1)
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
out[col + row] = a[row] * b0 + a[4 + row] * b1 + a[8 + row] * b2 + a[12 + row] * b3;
|
|
189
|
+
}
|
|
189
190
|
return out;
|
|
190
191
|
}
|
|
191
192
|
const translation = (x, y, z) => [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1];
|
|
@@ -213,11 +214,20 @@ export function cameraMatrix(view, at, distance) {
|
|
|
213
214
|
* surface swelled and shrank in steps.
|
|
214
215
|
*/
|
|
215
216
|
const num = (value) => {
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
if (value === 0)
|
|
218
|
+
return "0";
|
|
219
|
+
const text = value.toFixed(10);
|
|
220
|
+
// Without the zeros at the end, and the point if nothing is left after it: the same text as stripping them with a pattern, a good deal faster for the thousands of numbers a turn writes.
|
|
221
|
+
let end = text.length;
|
|
222
|
+
while (text.charCodeAt(end - 1) === 48)
|
|
223
|
+
end -= 1;
|
|
224
|
+
if (text.charCodeAt(end - 1) === 46)
|
|
225
|
+
end -= 1;
|
|
226
|
+
const out = end === text.length ? text : text.slice(0, end);
|
|
227
|
+
return out === "-0" ? "0" : out;
|
|
218
228
|
};
|
|
219
229
|
/** A matrix as the CSS `transform` that applies it. */
|
|
220
|
-
export const matrix3d = (m) => `matrix3d(${m
|
|
230
|
+
export const matrix3d = (m) => `matrix3d(${num(m[0])},${num(m[1])},${num(m[2])},${num(m[3])},${num(m[4])},${num(m[5])},${num(m[6])},${num(m[7])},${num(m[8])},${num(m[9])},${num(m[10])},${num(m[11])},${num(m[12])},${num(m[13])},${num(m[14])},${num(m[15])})`;
|
|
221
231
|
/** How far a point is from the eye's plane after the scene is turned and tipped, in pixels towards the eye: bigger is nearer. Planes are drawn far first. */
|
|
222
232
|
export function depthOf(point, view, at) {
|
|
223
233
|
const k = at.k * view.zoom;
|
package/dist/turn.dom.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type TurnDirection, type TurnPreset, type TurnView } from "./turn.camer
|
|
|
2
2
|
import { type TurnModel, type TurnSettings } from "./turn.model.ts";
|
|
3
3
|
import type { ScoreOptions, SurfaceOptions } from "./types.ts";
|
|
4
4
|
import type { VenueSettings } from "./venue.ts";
|
|
5
|
+
import { type Quality, type QualityTier } from "./quality.ts";
|
|
5
6
|
import type { OutsideLevel } from "./outside.paint.ts";
|
|
6
7
|
/** What `mountKyogijoTurn` gives back. `O` is what `update` takes: the options of a drawing, or (for `mountMultiTurn`) of a tournament layout. */
|
|
7
8
|
export interface KyogijoTurn<O = SurfaceOptions | ScoreOptions> {
|
|
@@ -43,6 +44,12 @@ export interface KyogijoTurn<O = SurfaceOptions | ScoreOptions> {
|
|
|
43
44
|
mode: string;
|
|
44
45
|
pixels: number;
|
|
45
46
|
} | undefined;
|
|
47
|
+
/** What the view was asked to draw: `auto`, or the tier it is held at. */
|
|
48
|
+
readonly quality: Quality;
|
|
49
|
+
/** The tier the view is drawn at now: what `quality` says, and for `auto` the one the frames have led it to (`high` at first). */
|
|
50
|
+
readonly tier: QualityTier;
|
|
51
|
+
/** Change what the view is asked to draw: a tier is taken at once, `auto` goes on from the tier it is at. The camera and the auto-turn are not touched. */
|
|
52
|
+
setQuality(quality: Quality): void;
|
|
46
53
|
/** The flat drawing that is the floor, or `null` after `destroy`. */
|
|
47
54
|
svg(): SVGSVGElement | null;
|
|
48
55
|
/** Stop listening and empty the container. */
|
package/dist/turn.dom.js
CHANGED
|
@@ -10,6 +10,8 @@ import { KYOGIJO_TURN_STYLE } from "./turn.style.js";
|
|
|
10
10
|
import { esc } from "./format.js";
|
|
11
11
|
import { turnBoardMarkup } from "./overlay.js";
|
|
12
12
|
import { attachOutside3d } from "./outside.dom.js";
|
|
13
|
+
import { TIER_PROFILES, createGovernor, handheld, layerBudget, qualityOf, rasterOf, rasterShares, tierOf } from "./quality.js";
|
|
14
|
+
import { size } from "./turn.kit.js";
|
|
13
15
|
/** True where the page can draw a plane in 3D by one `matrix3d`: that is, nearly everywhere with a stylesheet. */
|
|
14
16
|
export function turnSupported(win = typeof window === "undefined" ? undefined : window) {
|
|
15
17
|
const css = win?.CSS;
|
|
@@ -43,7 +45,33 @@ export function mountTurn(host, options, settings, build) {
|
|
|
43
45
|
const win = doc.defaultView;
|
|
44
46
|
/** The venue's settings as they are now: the mounted ones, altered by `update`. */
|
|
45
47
|
let venue = settings.venue;
|
|
46
|
-
|
|
48
|
+
// How much is drawn: what was asked, and the tier it is drawn at (`auto` starts on `high` and is moved by the frames the view makes while it turns).
|
|
49
|
+
let quality = qualityOf(settings.quality);
|
|
50
|
+
let tier = tierOf(quality);
|
|
51
|
+
// (Set again below, once the model is built, for a view that has no tiers.)
|
|
52
|
+
const isHandheld = handheld(win);
|
|
53
|
+
/** The share of its size each layer is made at for a model, now: one number when they all are, one each when the biggest are held to a budget of pixels. */
|
|
54
|
+
const rasterFor = (of) => {
|
|
55
|
+
// (Only a model that has tiers is made smaller: a surface on its own is small, and nothing of it would be left out.)
|
|
56
|
+
if (of.tiered !== true)
|
|
57
|
+
return 1;
|
|
58
|
+
const dpr = win?.devicePixelRatio ?? 1;
|
|
59
|
+
const share = rasterOf(quality, tier, dpr, isHandheld);
|
|
60
|
+
const budget = layerBudget(tier, isHandheld);
|
|
61
|
+
if (share === 1 && budget === Infinity)
|
|
62
|
+
return 1;
|
|
63
|
+
const boxes = [[of.viewBox.w * of.scale, of.viewBox.h * of.scale], ...of.planes.map((p) => { const [w, h] = size(p); return [w * of.scale, h * of.scale]; })];
|
|
64
|
+
return rasterShares(boxes, share, dpr, budget);
|
|
65
|
+
};
|
|
66
|
+
const sameRaster = (a, b) => (typeof a === "number" || typeof b === "number" ? a === b : a.length === b.length && a.every((x, i) => x === b[i]));
|
|
67
|
+
let current = options;
|
|
68
|
+
let model = build(options, { ...settings, quality: tier });
|
|
69
|
+
if (model.tiered !== true)
|
|
70
|
+
tier = "high";
|
|
71
|
+
let raster = rasterFor(model);
|
|
72
|
+
/** The models built at each tier for the options now, so that a step back to a tier is not built again. */
|
|
73
|
+
let made = new Map([[tier, model]]);
|
|
74
|
+
const baseId = model.id;
|
|
47
75
|
/** What names the four viewpoints: the model's own table (a tournament layout has one), else the sport's. */
|
|
48
76
|
const sport = () => model.presets ?? model.options.sport;
|
|
49
77
|
const supported = turnSupported(win ?? undefined) && model.turnable;
|
|
@@ -66,6 +94,9 @@ export function mountTurn(host, options, settings, build) {
|
|
|
66
94
|
direction: () => turnDirection(settings.direction),
|
|
67
95
|
setDirection: () => undefined,
|
|
68
96
|
togglePlay: () => false,
|
|
97
|
+
quality: qualityOf(settings.quality),
|
|
98
|
+
tier: tierOf(settings.quality),
|
|
99
|
+
setQuality: () => undefined,
|
|
69
100
|
update: (next, change) => {
|
|
70
101
|
if (change?.venue !== undefined)
|
|
71
102
|
venue = { ...(typeof venue === "object" ? venue : {}), ...change.venue };
|
|
@@ -79,7 +110,7 @@ export function mountTurn(host, options, settings, build) {
|
|
|
79
110
|
},
|
|
80
111
|
};
|
|
81
112
|
}
|
|
82
|
-
host.innerHTML = turnMarkupOf(model, settings);
|
|
113
|
+
host.innerHTML = turnMarkupOf(model, settings, raster);
|
|
83
114
|
const root = host.querySelector(".ky-turn");
|
|
84
115
|
const stage = root.querySelector(".ky-turn-view");
|
|
85
116
|
const live = root.querySelector(".ky-turn-live");
|
|
@@ -103,11 +134,14 @@ export function mountTurn(host, options, settings, build) {
|
|
|
103
134
|
let written = [];
|
|
104
135
|
let stacked = [];
|
|
105
136
|
let faded = [];
|
|
137
|
+
/** Which elements are left out of the view now (the faces of a solid that face away from the eye): they are not written to, and drawn at all, till the view turns them round. */
|
|
138
|
+
let gone = [];
|
|
106
139
|
const gather = () => {
|
|
107
140
|
elements = [...stage.querySelectorAll(".ky-turn-floor, .ky-up")];
|
|
108
141
|
written = elements.map((one) => one.style.transform);
|
|
109
142
|
stacked = elements.map((one) => one.style.zIndex);
|
|
110
143
|
faded = elements.map((one) => one.style.opacity);
|
|
144
|
+
gone = elements.map(() => false);
|
|
111
145
|
};
|
|
112
146
|
gather();
|
|
113
147
|
// The crowd outside, a canvas on the floor (the floor's matrix carries it), painted again only when its level, its detail or its colour changes.
|
|
@@ -116,8 +150,116 @@ export function mountTurn(host, options, settings, build) {
|
|
|
116
150
|
outside?.destroy();
|
|
117
151
|
const floor = stage.querySelector(".ky-turn-floor");
|
|
118
152
|
outside = model.outside === undefined || floor === null ? undefined : attachOutside3d(floor, model.outside);
|
|
153
|
+
outside?.setDetail(TIER_PROFILES[tier].outside);
|
|
119
154
|
};
|
|
120
155
|
crowd();
|
|
156
|
+
root.dataset.quality = quality;
|
|
157
|
+
root.dataset.tier = tier;
|
|
158
|
+
// ---- Quality: in `auto`, the frames the view makes while it turns decide the tier. ----
|
|
159
|
+
let governor = quality === "auto" && win !== null && model.tiered === true ? createGovernor(tier, settings.qualityTuning) : undefined;
|
|
160
|
+
let meterFrame;
|
|
161
|
+
let lastStamp;
|
|
162
|
+
let lastPaint = 0;
|
|
163
|
+
/** The display's own interval, measured once with nothing else going on: an idle loop of frames a moment after the mount (the lower decile of their intervals, so that a busy moment does not count). */
|
|
164
|
+
let probe;
|
|
165
|
+
let displayMs;
|
|
166
|
+
const probeDisplay = () => {
|
|
167
|
+
if (win === null || probe !== undefined || displayMs !== undefined)
|
|
168
|
+
return;
|
|
169
|
+
const found = [];
|
|
170
|
+
let before;
|
|
171
|
+
const step = (stamp) => {
|
|
172
|
+
probe = undefined;
|
|
173
|
+
if (!alive || win === null)
|
|
174
|
+
return;
|
|
175
|
+
if (doc.hidden === true) {
|
|
176
|
+
// Hidden: start over when it can be seen.
|
|
177
|
+
found.length = 0;
|
|
178
|
+
before = undefined;
|
|
179
|
+
probe = win.setTimeout(() => (probe = win.requestAnimationFrame(step)), 400);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (before !== undefined)
|
|
183
|
+
found.push(stamp - before);
|
|
184
|
+
before = stamp;
|
|
185
|
+
if (found.length < 24)
|
|
186
|
+
probe = win.requestAnimationFrame(step);
|
|
187
|
+
else {
|
|
188
|
+
displayMs = [...found].sort((a, b) => a - b)[Math.floor(found.length * 0.1)];
|
|
189
|
+
governor?.display(displayMs);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
probe = win.setTimeout(() => (probe = win.requestAnimationFrame(step)), 350);
|
|
193
|
+
};
|
|
194
|
+
const stopMeter = () => {
|
|
195
|
+
if (meterFrame !== undefined)
|
|
196
|
+
win?.cancelAnimationFrame(meterFrame);
|
|
197
|
+
meterFrame = undefined;
|
|
198
|
+
lastStamp = undefined;
|
|
199
|
+
};
|
|
200
|
+
if (governor !== undefined)
|
|
201
|
+
probeDisplay();
|
|
202
|
+
/** The loop that times the frames: it runs while the view is being painted and for a third of a second after, and does nothing while the view is still. */
|
|
203
|
+
const meterTick = (stamp) => {
|
|
204
|
+
meterFrame = undefined;
|
|
205
|
+
if (!alive || governor === undefined || win === null)
|
|
206
|
+
return;
|
|
207
|
+
if (doc.hidden === true || stamp - lastPaint > 300) {
|
|
208
|
+
lastStamp = undefined;
|
|
209
|
+
governor.pause();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const next = lastStamp === undefined ? undefined : governor.frame(stamp - lastStamp, stamp);
|
|
213
|
+
lastStamp = next === undefined ? stamp : undefined;
|
|
214
|
+
// (A step draws the view again, which asks for the loop itself: only one is ever running.)
|
|
215
|
+
if (next !== undefined)
|
|
216
|
+
retier(next);
|
|
217
|
+
if (meterFrame === undefined)
|
|
218
|
+
meterFrame = win.requestAnimationFrame(meterTick);
|
|
219
|
+
};
|
|
220
|
+
/** The view was painted: the frames are timed from now until it is still. */
|
|
221
|
+
const touched = () => {
|
|
222
|
+
if (governor === undefined || win === null)
|
|
223
|
+
return;
|
|
224
|
+
lastPaint = win.performance.now();
|
|
225
|
+
if (meterFrame === undefined)
|
|
226
|
+
meterFrame = win.requestAnimationFrame(meterTick);
|
|
227
|
+
};
|
|
228
|
+
/** Draw the world again, from the model of the tier and the options now: the camera, the auto-turn and the pointer are not touched (the elements are the only thing replaced). */
|
|
229
|
+
const renderWorld = () => {
|
|
230
|
+
const known = made.get(tier);
|
|
231
|
+
model = known ?? build(current, { ...settings, quality: tier, id: settings.id ?? baseId, venue, preset: undefined, view });
|
|
232
|
+
made.set(tier, model);
|
|
233
|
+
raster = rasterFor(model);
|
|
234
|
+
const layout = layoutOf(model, shown, stage.clientWidth || 960, stage.clientHeight || 600, settings.lens, false, raster);
|
|
235
|
+
const world = root.querySelector(".ky-turn-world");
|
|
236
|
+
world.innerHTML = worldMarkup(model, layout, raster);
|
|
237
|
+
// The look the floor is painted in (and the theme) are attributes of the world.
|
|
238
|
+
for (const name of ["data-sport", "data-look", "data-theme"])
|
|
239
|
+
world.removeAttribute(name);
|
|
240
|
+
world.className = model.look === undefined ? "ky-turn-world" : "ky-turn-world kyogijo";
|
|
241
|
+
if (model.look !== undefined) {
|
|
242
|
+
world.setAttribute("data-sport", model.look.sport);
|
|
243
|
+
world.setAttribute("data-look", model.look.look);
|
|
244
|
+
const forced = model.options.theme;
|
|
245
|
+
if (forced === "light" || forced === "dark")
|
|
246
|
+
world.setAttribute("data-theme", forced);
|
|
247
|
+
}
|
|
248
|
+
gather();
|
|
249
|
+
crowd();
|
|
250
|
+
root.dataset.quality = quality;
|
|
251
|
+
root.dataset.tier = tier;
|
|
252
|
+
};
|
|
253
|
+
/** The governor stepped: draw at the new tier. */
|
|
254
|
+
const retier = (next) => {
|
|
255
|
+
if (next === tier)
|
|
256
|
+
return;
|
|
257
|
+
tier = next;
|
|
258
|
+
renderWorld();
|
|
259
|
+
paint(shown);
|
|
260
|
+
label();
|
|
261
|
+
settings.onQualityChange?.(tier, quality);
|
|
262
|
+
};
|
|
121
263
|
const buttons = () => root.querySelectorAll("button[data-preset]");
|
|
122
264
|
/** The Play button says what it is and what it does: pressed while the view turns. */
|
|
123
265
|
const syncPlay = () => {
|
|
@@ -135,9 +277,18 @@ export function mountTurn(host, options, settings, build) {
|
|
|
135
277
|
const paint = (now) => {
|
|
136
278
|
const width = stage.clientWidth || 960;
|
|
137
279
|
const height = stage.clientHeight || 600;
|
|
138
|
-
const layout = layoutOf(model, now, width, height, settings.lens);
|
|
280
|
+
const layout = layoutOf(model, now, width, height, settings.lens, true, raster);
|
|
139
281
|
outside?.zoom(now.zoom);
|
|
282
|
+
const culled = layout.culled;
|
|
140
283
|
elements.forEach((one, i) => {
|
|
284
|
+
// A face turned away from the eye is hidden by the solid it belongs to: it is taken out of the page's drawing, not written to.
|
|
285
|
+
const away = culled?.[i] === true;
|
|
286
|
+
if (away !== gone[i]) {
|
|
287
|
+
one.style.display = away ? "none" : "";
|
|
288
|
+
gone[i] = away;
|
|
289
|
+
}
|
|
290
|
+
if (away)
|
|
291
|
+
return;
|
|
141
292
|
if (written[i] !== layout.transforms[i])
|
|
142
293
|
one.style.transform = written[i] = layout.transforms[i];
|
|
143
294
|
const z = String(layout.stack[i]);
|
|
@@ -147,6 +298,7 @@ export function mountTurn(host, options, settings, build) {
|
|
|
147
298
|
if (faded[i] !== o)
|
|
148
299
|
one.style.opacity = faded[i] = o;
|
|
149
300
|
});
|
|
301
|
+
touched();
|
|
150
302
|
};
|
|
151
303
|
const label = () => {
|
|
152
304
|
const here = presetOf(view, sport());
|
|
@@ -469,25 +621,11 @@ export function mountTurn(host, options, settings, build) {
|
|
|
469
621
|
return;
|
|
470
622
|
if (change?.venue !== undefined)
|
|
471
623
|
venue = { ...(typeof venue === "object" ? venue : {}), ...change.venue };
|
|
472
|
-
|
|
624
|
+
current = next;
|
|
625
|
+
made = new Map();
|
|
473
626
|
view = clampView(view);
|
|
627
|
+
renderWorld();
|
|
474
628
|
opening = openingView(settings, sport());
|
|
475
|
-
const layout = layoutOf(model, shown, stage.clientWidth || 960, stage.clientHeight || 600, settings.lens);
|
|
476
|
-
const world = root.querySelector(".ky-turn-world");
|
|
477
|
-
world.innerHTML = worldMarkup(model, layout);
|
|
478
|
-
// The look the floor is painted in (and the theme) are attributes of the world.
|
|
479
|
-
for (const name of ["data-sport", "data-look", "data-theme"])
|
|
480
|
-
world.removeAttribute(name);
|
|
481
|
-
world.className = model.look === undefined ? "ky-turn-world" : "ky-turn-world kyogijo";
|
|
482
|
-
if (model.look !== undefined) {
|
|
483
|
-
world.setAttribute("data-sport", model.look.sport);
|
|
484
|
-
world.setAttribute("data-look", model.look.look);
|
|
485
|
-
const forced = model.options.theme;
|
|
486
|
-
if (forced === "light" || forced === "dark")
|
|
487
|
-
world.setAttribute("data-theme", forced);
|
|
488
|
-
}
|
|
489
|
-
gather();
|
|
490
|
-
crowd();
|
|
491
629
|
// The board is a layer of its own over the view, after the scene: it is written again, and the view's turn is not touched.
|
|
492
630
|
stage.querySelector(".ky-turn-board")?.remove();
|
|
493
631
|
if (model.board !== undefined)
|
|
@@ -513,6 +651,45 @@ export function mountTurn(host, options, settings, build) {
|
|
|
513
651
|
get playing() {
|
|
514
652
|
return playing;
|
|
515
653
|
},
|
|
654
|
+
get quality() {
|
|
655
|
+
return quality;
|
|
656
|
+
},
|
|
657
|
+
get tier() {
|
|
658
|
+
return tier;
|
|
659
|
+
},
|
|
660
|
+
setQuality(asked) {
|
|
661
|
+
if (!alive)
|
|
662
|
+
return;
|
|
663
|
+
quality = qualityOf(asked, quality);
|
|
664
|
+
const was = tier;
|
|
665
|
+
if (model.tiered !== true) {
|
|
666
|
+
// A view that has no tiers draws as it does whatever is asked: the question is kept, and answered `high`.
|
|
667
|
+
governor = undefined;
|
|
668
|
+
stopMeter();
|
|
669
|
+
tier = "high";
|
|
670
|
+
}
|
|
671
|
+
else if (quality === "auto") {
|
|
672
|
+
stopMeter();
|
|
673
|
+
governor = win === null ? undefined : createGovernor(tier, settings.qualityTuning);
|
|
674
|
+
if (displayMs !== undefined)
|
|
675
|
+
governor?.display(displayMs);
|
|
676
|
+
else
|
|
677
|
+
probeDisplay();
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
governor = undefined;
|
|
681
|
+
stopMeter();
|
|
682
|
+
tier = quality;
|
|
683
|
+
}
|
|
684
|
+
root.dataset.quality = quality;
|
|
685
|
+
// The tier, or the share its layers are made at, has changed: the world is drawn again (the shares are worked out for the model of the tier, in `renderWorld`).
|
|
686
|
+
if (tier !== was || !sameRaster(rasterFor(model), raster)) {
|
|
687
|
+
renderWorld();
|
|
688
|
+
paint(shown);
|
|
689
|
+
label();
|
|
690
|
+
}
|
|
691
|
+
settings.onQualityChange?.(tier, quality);
|
|
692
|
+
},
|
|
516
693
|
play() {
|
|
517
694
|
setPlaying(true);
|
|
518
695
|
return playing;
|
|
@@ -545,6 +722,7 @@ export function mountTurn(host, options, settings, build) {
|
|
|
545
722
|
outside?.destroy();
|
|
546
723
|
stop();
|
|
547
724
|
stopTick();
|
|
725
|
+
stopMeter();
|
|
548
726
|
seen?.disconnect();
|
|
549
727
|
doc.removeEventListener("visibilitychange", onVisible);
|
|
550
728
|
clearTimeout(spoken);
|
package/dist/turn.kit.d.ts
CHANGED
|
@@ -40,6 +40,11 @@ export interface Plane {
|
|
|
40
40
|
* (a raised room is seen through every wall between it and the eye, at a low angle and from straight above alike).
|
|
41
41
|
*/
|
|
42
42
|
fadeSide?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* A face of a closed solid that nothing shows through (a building's wall, drawn opaque): the side of it that is the solid's outside, as the way its `u` x `v` points, 1 out of the solid and -1 into it. While the face is turned away
|
|
45
|
+
* from the eye it is hidden by the solid's own near faces, so a page that asks for it (`layoutOf`'s `cull`) leaves it out of the view until the view turns it round, and spends nothing on it.
|
|
46
|
+
*/
|
|
47
|
+
cull?: 1 | -1;
|
|
43
48
|
/** A plate the other planes of its building stand on (a floor of a building picked out): it is placed by its farthest corner, so that it is drawn under everything on it, whatever way the view turns. */
|
|
44
49
|
under?: boolean;
|
|
45
50
|
/**
|
package/dist/turn.markup.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { type Placement, type TurnDirection, type TurnView } from "./turn.camera
|
|
|
2
2
|
import { type Plane } from "./turn.kit.ts";
|
|
3
3
|
import { type TurnModel, type TurnSettings } from "./turn.model.ts";
|
|
4
4
|
import type { ScoreOptions, SurfaceOptions } from "./types.ts";
|
|
5
|
+
/** The share of its size each layer is made at: one number for all, or one for each (the floor first, then the planes in the model's order). */
|
|
6
|
+
export type Raster = number | readonly number[];
|
|
5
7
|
/**
|
|
6
8
|
* The matrix that stands a plane in the scene, before the camera: its x along `u`, its y along `v`, its corner `o`, in pixels from the middle of the scene
|
|
7
9
|
* (`centre`, in feet).
|
|
@@ -17,24 +19,30 @@ export declare function groupRanks(groups: readonly {
|
|
|
17
19
|
/** Where everything is for a view in a container: the placement, the matrix of each element and its place in the stack. */
|
|
18
20
|
export interface Layout {
|
|
19
21
|
at: Placement;
|
|
20
|
-
/** The floor, then the planes in the model's order. */
|
|
22
|
+
/** The floor, then the planes in the model's order. A plane that `cull` says is turned away has `""` here. */
|
|
21
23
|
transforms: string[];
|
|
22
24
|
/** The stack of each: 0 for the ground of a hall, 1 for the floor, then the planes far to near from 2. */
|
|
23
25
|
stack: number[];
|
|
24
26
|
/** How much of each is left: 1 for all but the walls that are between the eye and the surface, which are cut away as the view is low and on their side (`fadeOf`). */
|
|
25
27
|
fade: number[];
|
|
28
|
+
/** Which elements are not drawn at this view, by their place in `transforms`: the faces of a closed solid that are turned away from the eye (`Plane.cull`). Only when `layoutOf` was asked to leave them out. */
|
|
29
|
+
culled?: boolean[];
|
|
26
30
|
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Work a view out in a container `width` by `height` pixels. With `cull`, the faces of a closed solid that are turned away from the eye (`Plane.cull`) are left out: they have no transform and no place in the stack, and `culled` says
|
|
33
|
+
* which, so that a page need not write them at all; without it every plane is laid out, as a still picture needs. `raster` is the share of its size an element is made at (`rasterOf`): each element's matrix widens it back, so that the
|
|
34
|
+
* picture is the same and the layers hold `raster` squared as many pixels.
|
|
35
|
+
*/
|
|
36
|
+
export declare function layoutOf(model: TurnModel, view: TurnView, width: number, height: number, lens?: number, cull?: boolean, raster?: Raster): Layout;
|
|
29
37
|
/** One plane as an element: its box in pixels and the SVG drawn on it in feet. */
|
|
30
|
-
export declare function planeMarkup(p: Plane, scale: number, transform: string, stack: number, fade?: number): string;
|
|
38
|
+
export declare function planeMarkup(p: Plane, scale: number, transform: string, stack: number, fade?: number, raster?: number): string;
|
|
31
39
|
/**
|
|
32
40
|
* A plane that is the floor's own drawing seen through its rectangle (`Plane.crop`): the floor's SVG again, its viewBox cut down to the plane's rectangle, in the plane's own box. It is a picture, not a second
|
|
33
41
|
* description: it carries no role, title or description of its own.
|
|
34
42
|
*/
|
|
35
|
-
export declare function cropMarkup(model: TurnModel, p: Plane, transform: string, stack: number, fade?: number): string;
|
|
43
|
+
export declare function cropMarkup(model: TurnModel, p: Plane, transform: string, stack: number, fade?: number, raster?: number): string;
|
|
36
44
|
/** The floor as an element: the flat drawing, in the pixels of the scene. */
|
|
37
|
-
export declare function floorMarkup(model: TurnModel, transform: string, stack: number): string;
|
|
45
|
+
export declare function floorMarkup(model: TurnModel, transform: string, stack: number, raster?: number): string;
|
|
38
46
|
/** The patterns the venue's planes are drawn with, once, in a box of no size: every plane's SVG reads them by id, and the crowd's colours are on this element. */
|
|
39
47
|
export declare function defsMarkup(model: TurnModel): string;
|
|
40
48
|
/**
|
|
@@ -43,7 +51,7 @@ export declare function defsMarkup(model: TurnModel): string;
|
|
|
43
51
|
*/
|
|
44
52
|
export declare function worldAttributes(model: TurnModel): string;
|
|
45
53
|
/** The floor and the planes of a model, laid out. */
|
|
46
|
-
export declare function worldMarkup(model: TurnModel, layout: Layout): string;
|
|
54
|
+
export declare function worldMarkup(model: TurnModel, layout: Layout, raster?: Raster): string;
|
|
47
55
|
/** The buttons under the view. */
|
|
48
56
|
export declare function controlsMarkup(model: TurnModel, view: TurnView, playing?: boolean, direction?: TurnDirection): string;
|
|
49
57
|
/** The size, in pixels, the first view is worked out for. */
|
|
@@ -52,7 +60,7 @@ export declare const sizeOf: (settings: TurnSettings) => {
|
|
|
52
60
|
height: number;
|
|
53
61
|
};
|
|
54
62
|
/** The 3D view of a model as markup, laid out for `settings.size`; a page's script then makes it turn. */
|
|
55
|
-
export declare function turnMarkupOf(model: TurnModel, settings?: TurnSettings): string;
|
|
63
|
+
export declare function turnMarkupOf(model: TurnModel, settings?: TurnSettings, raster?: Raster): string;
|
|
56
64
|
/**
|
|
57
65
|
* A surface as a 3D view, as markup: the flat drawing for a floor, what stands on it as planes, and the controls under it. Pure, so it can be made on a
|
|
58
66
|
* server; it is a still picture until `mountKyogijoTurn` (or the element) makes it turn in a page.
|