Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #56

Merged
merged 12 commits into from
Dec 30, 2024
5 changes: 1 addition & 4 deletions cafe/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,5 @@ body {
height: 100%;
overflow: hidden;
background: rgb(0, 0, 0);
background: linear-gradient(0deg,
rgba(0, 0, 0, 1) 0%,
rgba(17, 17, 17, 1) 35%,
rgba(53, 53, 53, 1) 100%);
background: linear-gradient(1deg, rgba(236, 236, 172, 1) 0%, rgba(247, 255, 71, 1) 11%, rgba(0, 0, 0, 1) 16%, rgba(247, 255, 71, 1) 20%, rgba(74, 42, 42, 1) 100%);
}
4 changes: 2 additions & 2 deletions cafe/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<link rel="manifest" href="./manifest.webmanifest" />
<meta name="viewport" content="width=device-width, initial-scale=0.86, maximum-scale=3.0, minimum-scale=0.86" />
<link rel="icon" type="image/x-icon" href="./favicon.ico" />
<link rel="manifest" href="./manifest.webmanifest" />
<link rel="stylesheet" href="./index.css" />
<!-- Start Single Page Apps for GitHub Pages -->
<script type="text/javascript">
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "zed-software-system",
"private": true,
"version": "0.21.1",
"version": "0.21.7",
"type": "module",
"scripts": {
"sloc": "npx sloc zss",
Expand Down
2 changes: 1 addition & 1 deletion zss/gadget/data/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const useTape = create<{
title: string
}
}>(() => ({
layout: TAPE_DISPLAY.BOTTOM,
layout: TAPE_DISPLAY.TOP,
terminal: {
open: true,
level: TAPE_LOG_LEVEL.INFO,
Expand Down
26 changes: 12 additions & 14 deletions zss/gadget/layout.tsx → zss/gadget/panellayout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useThree } from '@react-three/fiber'
import { deepClone, _areEquals } from 'fast-json-patch'
import React, { useState } from 'react'
import { RUNTIME } from 'zss/config'
Expand All @@ -14,6 +13,7 @@ import { StaticDither } from './framed/dither'
import { Panel } from './panel'
import { ScrollContext } from './panel/common'
import { Scroll } from './scroll'
import { useScreenSize } from './userscreen'

enum RECT_TYPE {
PANEL,
Expand Down Expand Up @@ -67,21 +67,15 @@ function LayoutRect({ rect, shouldclose = false }: LayoutRectProps) {
return null
}

export function Layout() {
const viewport = useThree((state) => state.viewport)
const { width: viewWidth, height: viewHeight } = viewport.getCurrentViewport()

const width = Math.floor(viewWidth / RUNTIME.DRAW_CHAR_WIDTH())
const height = Math.floor(viewHeight / RUNTIME.DRAW_CHAR_HEIGHT())
const marginX = viewWidth - width * RUNTIME.DRAW_CHAR_WIDTH()
const marginY = viewHeight - height * RUNTIME.DRAW_CHAR_HEIGHT()
export function PanelLayout() {
const screensize = useScreenSize()

// cache scroll
const [scroll, setScroll] = useState<RECT>()
const panels = useGadgetClient(useEqual((state) => state.gadget.panels))

// bail on odd states
if (width < 1 || height < 1) {
if (screensize.cols < 10 || screensize.rows < 10) {
return null
}

Expand All @@ -91,9 +85,9 @@ export function Layout() {
type: RECT_TYPE.FRAMED,
x: 0,
y: 0,
width,
height,
text: [],
width: screensize.cols,
height: screensize.rows,
}

// iterate layout
Expand Down Expand Up @@ -204,7 +198,7 @@ export function Layout() {
}}
>
{/* eslint-disable-next-line react/no-unknown-property */}
<group position={[marginX * 0.5, marginY * 0.5, -512]}>
<group position={[0, 0, -512]}>
{rects.map((rect) => {
return (
<group
Expand All @@ -226,7 +220,11 @@ export function Layout() {
// eslint-disable-next-line react/no-unknown-property
position={[0, 0, 800]}
>
<StaticDither width={width} height={height} alpha={0.14} />
<StaticDither
width={screensize.cols}
height={screensize.rows}
alpha={0.14}
/>
</group>
<group
// eslint-disable-next-line react/no-unknown-property
Expand Down
76 changes: 27 additions & 49 deletions zss/gadget/tape.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable react/no-unknown-property */
import { useThree } from '@react-three/fiber'
import { RUNTIME } from 'zss/config'
import { tape_terminal_open } from 'zss/device/api'
Expand All @@ -15,56 +16,41 @@ import { BackPlate } from './tape/backplate'
import { BG, FG } from './tape/common'
import { TapeLayout } from './tape/layout'
import { UserFocus, UserHotkey } from './userinput'
import { useScreenSize } from './userscreen'
import { TilesData, TilesRender } from './usetiles'

export function Tape() {
const viewport = useThree((state) => state.viewport)
const { width: viewWidth, height: viewHeight } = viewport.getCurrentViewport()

const ditherwidth = Math.floor(viewWidth / RUNTIME.DRAW_CHAR_WIDTH())
const ditherheight = Math.floor(viewHeight / RUNTIME.DRAW_CHAR_HEIGHT())

// sizing
const SCALE = 1
const CHAR_WIDTH = RUNTIME.DRAW_CHAR_WIDTH() * SCALE
const CHAR_HEIGHT = RUNTIME.DRAW_CHAR_HEIGHT() * SCALE

const cols = Math.floor(viewWidth / CHAR_WIDTH)
const rows = Math.floor(viewHeight / CHAR_HEIGHT)
const marginx = viewWidth - cols * CHAR_WIDTH
const marginy = viewHeight - rows * CHAR_HEIGHT
const screensize = useScreenSize()

let top = 0
const left = 0
const width = cols
let height = rows
let height = screensize.rows

const [layout, terminalopen] = useTape(
useShallow((state) => [state.layout, state.terminal.open]),
)

switch (layout) {
case TAPE_DISPLAY.TOP:
height = Math.round(rows * 0.5)
height = Math.round(screensize.rows * 0.5)
break
case TAPE_DISPLAY.BOTTOM:
height = Math.round(rows * 0.5)
top = rows - height
height = Math.round(screensize.rows * 0.5)
top = screensize.rows - height
break
default:
case TAPE_DISPLAY.FULL:
// defaults
break
}

const store = useTiles(width, height, 0, FG, BG)
const store = useTiles(screensize.cols, height, 0, FG, BG)
const context: WRITE_TEXT_CONTEXT = {
...createwritetextcontext(width, height, FG, BG),
...createwritetextcontext(screensize.cols, height, FG, BG),
...store.getState(),
}

// bail on odd states
if (width < 1 || height < 1) {
if (screensize.cols < 10 || screensize.rows < 10) {
return null
}

Expand All @@ -78,35 +64,27 @@ export function Tape() {
>
{terminalopen && (
<ShadeBoxDither
width={ditherwidth}
height={ditherheight}
width={screensize.cols}
height={screensize.rows}
top={top}
left={left}
right={left + width - 1}
left={0}
right={screensize.cols - 1}
bottom={top + height - 1}
/>
)}
<group
// eslint-disable-next-line react/no-unknown-property
position={[
marginx * 0.5 + left * CHAR_WIDTH,
marginy + top * CHAR_HEIGHT,
1,
]}
scale={[SCALE, SCALE, 1.0]}
>
{terminalopen ? (
<UserFocus blockhotkeys>
<BackPlate context={context} />
<TapeLayout context={context} />
<TilesRender width={width} height={height} />
</UserFocus>
) : (
<UserHotkey hotkey="Shift+?">
{() => tape_terminal_open('tape', player)}
</UserHotkey>
)}
</group>
{terminalopen ? (
<UserFocus blockhotkeys>
<BackPlate context={context} />
<TapeLayout context={context} />
<group position={[0, top * RUNTIME.DRAW_CHAR_HEIGHT(), 0]}>
<TilesRender width={screensize.cols} height={height} />
</group>
</UserFocus>
) : (
<UserHotkey hotkey="Shift+?">
{() => tape_terminal_open('tape', player)}
</UserHotkey>
)}
</group>
</TilesData>
)
Expand Down
88 changes: 41 additions & 47 deletions zss/gadget/terminal.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,36 @@
import { addEffect, addAfterEffect, useThree, extend } from '@react-three/fiber'
import { EffectComposer } from '@react-three/postprocessing'
import { getGPUTier, TierResult } from 'detect-gpu'
import { useEffect, useLayoutEffect, useRef, useState } from 'react'
import { deviceType, primaryInput } from 'detect-it'
import { useEffect, useState } from 'react'
import Stats from 'stats.js'
import { NearestFilter, OrthographicCamera } from 'three'
import { FORCE_CRT_OFF, STATS_DEV } from 'zss/config'
import { api_error } from 'zss/device/api'
import { FORCE_CRT_OFF, RUNTIME, STATS_DEV } from 'zss/config'
import { CRTShape } from 'zss/gadget/fx/crt'
import decoimageurl from 'zss/gadget/fx/scratches.gif'
import { useTexture } from 'zss/gadget/usetexture'
import { doasync } from 'zss/mapping/func'

import { Layout } from './layout'
import { PanelLayout } from './panellayout'
import { Tape } from './tape'
import { UserFocus } from './userinput'
import { UserScreen } from './userscreen'

// include all front-end devices
import 'zss/userspace'

extend({ OrthographicCamera })

export function Terminal() {
const viewport = useThree((state) => state.viewport)
const cameraRef = useRef<OrthographicCamera>(null)
const { viewport } = useThree()
const { width: viewwidth, height: viewheight } = viewport.getCurrentViewport()

const splat = useTexture(decoimageurl)
splat.minFilter = NearestFilter
splat.magFilter = NearestFilter

// handle showing render stats
const [stats] = useState(() => new Stats())

useEffect(() => {
if (!STATS_DEV) {
return
}

document.body.appendChild(stats.dom)
stats.showPanel(0)
stats.dom.style.cssText = 'position:fixed;bottom:0;left:0;'
Expand All @@ -47,52 +43,50 @@ export function Terminal() {
}
}, [stats])

// detect gpu info
const [gputier, setgputier] = useState<TierResult>()
useEffect(() => {
getGPUTier({
benchmarksURL: '/benchmarks-min',
doasync('gpudetect', async () => {
const result = await getGPUTier({ benchmarksURL: '/benchmarks-min' })
setgputier(result)
})
.then(setgputier)
.catch((err) => api_error('gpu', 'detect', err))
}, [])

const shouldcrt =
!FORCE_CRT_OFF && gputier && gputier.tier > 2 && !gputier.isMobile
// config DRAW_CHAR_SCALE
const minrez = Math.min(viewwidth, viewheight)
const islowrez = minrez < 600
RUNTIME.DRAW_CHAR_SCALE = islowrez ? 1 : 2

const set = useThree(({ set }) => set)
const size = useThree(({ size }) => size)
const camera = useThree(({ camera }) => camera)
// config LAYOUT
const islandscape = viewwidth > viewheight
const showtouchcontrols = deviceType === 'hybrid' || primaryInput === 'touch'

useLayoutEffect(() => {
cameraRef.current?.updateProjectionMatrix()
})
// grit texture
const splat = useTexture(decoimageurl)
splat.minFilter = NearestFilter
splat.magFilter = NearestFilter

useLayoutEffect(() => {
const oldCam = camera
set(() => ({ camera: cameraRef.current! }))
return () => set(() => ({ camera: oldCam }))
}, [set, camera, cameraRef])
// config FX
const shouldcrt =
!FORCE_CRT_OFF &&
!islowrez &&
!showtouchcontrols &&
gputier &&
gputier.tier > 2 &&
!gputier.isMobile

return (
<>
<orthographicCamera
ref={cameraRef}
left={size.width / -2}
right={size.width / 2}
top={size.height / 2}
bottom={size.height / -2}
near={1}
far={2000}
position={[0, 0, 1000]}
/>
<group scale-x={-1} rotation-z={Math.PI}>
<group position={[viewwidth * -0.5, viewheight * -0.5, 0]}>
<UserFocus>
<Layout />
<Tape />
</UserFocus>
</group>
</group>
<UserFocus>
<UserScreen
islowrez={islowrez}
islandscape={islandscape}
showtouchcontrols={showtouchcontrols}
>
<PanelLayout />
<Tape />
</UserScreen>
</UserFocus>
{shouldcrt && (
<EffectComposer>
<CRTShape splat={splat} viewheight={viewheight} />
Expand Down
Loading
Loading