Initial visionLabs Roku scaffold
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
dist/
|
||||||
|
out/
|
||||||
|
*.pkg
|
||||||
|
*.zip
|
||||||
37
README.md
Normal file
37
README.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# visionLabs Roku
|
||||||
|
|
||||||
|
visionLabs Roku is a private Roku app scaffold for viewing home security cameras on a TV.
|
||||||
|
|
||||||
|
## Product direction
|
||||||
|
|
||||||
|
- Brand family follows the user's existing `Labs` naming pattern.
|
||||||
|
- V1 uses a static packaged camera configuration.
|
||||||
|
- V2 adds in-app camera and layout editing.
|
||||||
|
- V3 moves camera metadata and layout persistence to a backend service.
|
||||||
|
|
||||||
|
## Technical direction
|
||||||
|
|
||||||
|
- Roku SceneGraph app
|
||||||
|
- Camera feeds delivered as HLS where possible
|
||||||
|
- Static JSON config for the first prototype
|
||||||
|
- Future backend for editing, persistence, and auth
|
||||||
|
|
||||||
|
## Project layout
|
||||||
|
|
||||||
|
- `manifest` - Roku channel metadata
|
||||||
|
- `source/main.brs` - app entry point
|
||||||
|
- `components/MainScene.xml` - initial SceneGraph UI
|
||||||
|
- `components/MainScene.brs` - scene behavior
|
||||||
|
- `config/cameras.json` - static sample camera config
|
||||||
|
- `docs/ROADMAP.md` - delivery phases and constraints
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Roku is not a great target for raw RTSP feeds. The clean path is to expose camera streams as HLS, either directly from the NVR or through a relay/transcoder layer.
|
||||||
|
|
||||||
|
## Next steps
|
||||||
|
|
||||||
|
1. Replace sample camera URLs in `config/cameras.json`
|
||||||
|
2. Load config into the UI
|
||||||
|
3. Render a static multi-camera grid
|
||||||
|
4. Add edit mode and persistence strategy
|
||||||
3
components/MainScene.brs
Normal file
3
components/MainScene.brs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
sub init()
|
||||||
|
m.top.setFocus(true)
|
||||||
|
end sub
|
||||||
32
components/MainScene.xml
Normal file
32
components/MainScene.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<component name="MainScene" extends="Scene">
|
||||||
|
<script type="text/brightscript" uri="pkg:/components/MainScene.brs" />
|
||||||
|
|
||||||
|
<children>
|
||||||
|
<Rectangle id="bg" color="0x101418FF" width="1920" height="1080" />
|
||||||
|
<Label
|
||||||
|
id="title"
|
||||||
|
translation="[80, 80]"
|
||||||
|
width="1760"
|
||||||
|
height="60"
|
||||||
|
text="visionLabs"
|
||||||
|
font="font:LargeBoldSystemFont"
|
||||||
|
color="0xFFFFFFFF" />
|
||||||
|
<Label
|
||||||
|
id="subtitle"
|
||||||
|
translation="[80, 150]"
|
||||||
|
width="1760"
|
||||||
|
height="40"
|
||||||
|
text="Labs camera viewer for Roku"
|
||||||
|
font="font:MediumSystemFont"
|
||||||
|
color="0xC9D1D9FF" />
|
||||||
|
<Label
|
||||||
|
id="status"
|
||||||
|
translation="[80, 260]"
|
||||||
|
width="1760"
|
||||||
|
height="120"
|
||||||
|
text="Project scaffold is live. Next step: load static cameras.json and render HLS camera tiles."
|
||||||
|
font="font:MediumSystemFont"
|
||||||
|
color="0x8B949EFF" />
|
||||||
|
</children>
|
||||||
|
</component>
|
||||||
34
config/cameras.json
Normal file
34
config/cameras.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"appName": "visionLabs",
|
||||||
|
"layout": {
|
||||||
|
"type": "grid",
|
||||||
|
"columns": 2,
|
||||||
|
"rows": 2
|
||||||
|
},
|
||||||
|
"cameras": [
|
||||||
|
{
|
||||||
|
"id": "front-door",
|
||||||
|
"name": "Front Door",
|
||||||
|
"streamUrl": "https://example.invalid/front-door/index.m3u8",
|
||||||
|
"snapshotUrl": "https://example.invalid/front-door.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "driveway",
|
||||||
|
"name": "Driveway",
|
||||||
|
"streamUrl": "https://example.invalid/driveway/index.m3u8",
|
||||||
|
"snapshotUrl": "https://example.invalid/driveway.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "garage",
|
||||||
|
"name": "Garage",
|
||||||
|
"streamUrl": "https://example.invalid/garage/index.m3u8",
|
||||||
|
"snapshotUrl": "https://example.invalid/garage.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "back-yard",
|
||||||
|
"name": "Back Yard",
|
||||||
|
"streamUrl": "https://example.invalid/back-yard/index.m3u8",
|
||||||
|
"snapshotUrl": "https://example.invalid/back-yard.jpg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
32
docs/ROADMAP.md
Normal file
32
docs/ROADMAP.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# visionLabs Roku roadmap
|
||||||
|
|
||||||
|
## Phase 1
|
||||||
|
|
||||||
|
- Static packaged camera config
|
||||||
|
- Simple Roku SceneGraph shell
|
||||||
|
- One screen with a fixed camera grid
|
||||||
|
- HLS-backed streams only
|
||||||
|
|
||||||
|
## Phase 2
|
||||||
|
|
||||||
|
- Config loader and camera tile rendering
|
||||||
|
- Snapshot fallback if a stream is unavailable
|
||||||
|
- Focus movement and remote navigation
|
||||||
|
|
||||||
|
## Phase 3
|
||||||
|
|
||||||
|
- In-app edit mode for camera names and layout
|
||||||
|
- Persistence strategy for edits
|
||||||
|
- Basic app settings screen
|
||||||
|
|
||||||
|
## Phase 4
|
||||||
|
|
||||||
|
- Backend API for camera registry and layout
|
||||||
|
- Authentication and access control
|
||||||
|
- Multiple saved layouts
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- Roku does not directly fit raw RTSP workflows well
|
||||||
|
- HLS is the safest first-class playback target
|
||||||
|
- Packaged JSON is fine for V1 but not enough for runtime editing
|
||||||
6
manifest
Normal file
6
manifest
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
title=visionLabs
|
||||||
|
subtitle=Labs home camera viewer
|
||||||
|
major_version=0
|
||||||
|
minor_version=1
|
||||||
|
build_version=1
|
||||||
|
ui_resolutions=hd,fhd
|
||||||
15
source/main.brs
Normal file
15
source/main.brs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
sub Main()
|
||||||
|
screen = CreateObject("roSGScreen")
|
||||||
|
port = CreateObject("roMessagePort")
|
||||||
|
screen.SetMessagePort(port)
|
||||||
|
|
||||||
|
scene = screen.CreateScene("MainScene")
|
||||||
|
screen.Show()
|
||||||
|
|
||||||
|
while true
|
||||||
|
msg = wait(0, port)
|
||||||
|
if type(msg) = "roSGScreenEvent" and msg.IsScreenClosed() then
|
||||||
|
return
|
||||||
|
end if
|
||||||
|
end while
|
||||||
|
end sub
|
||||||
Reference in New Issue
Block a user